From 3edcf5a70b11ae9a9e0d9d15d5c0a03867cbc4b5 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 21:54:47 -0800 Subject: [PATCH 01/12] fix: add prettier rule to enforce short lines in for-developers --- .prettierrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.prettierrc b/.prettierrc index 3200055..d30dcc5 100644 --- a/.prettierrc +++ b/.prettierrc @@ -21,6 +21,15 @@ "options": { "singleQuote": false } + }, + { + "files": "for-developers/**/*.md, for-developers/**/*.mdx", + "options": { + "proseWrap": "always", + "printWidth": 80, + "useTabs": false, + "tabWidth": 2 + } } ] } From 1251234033ea2641dd790bc78755e3ffaa0a71e5 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 15:12:31 -0800 Subject: [PATCH 02/12] Remove trailing spaces This prevent word-wrap, which often ends up looking odd in the browser ("paragraphs" without proper separation). --- for-developers/Satellite-API.md | 10 +++++----- .../core-development/development-flow.md | 2 +- for-developers/git-workflows/versioning.md | 4 ++-- .../module-development/api-changes/v1.12.md | 2 +- .../module-development/api-changes/v1.5.md | 2 +- .../module-development/api-changes/v1.8.md | 4 ++-- .../bonjour-device-discovery.md | 6 +++--- .../migrating-legacy-to-boolean-feedbacks.md | 4 ++-- .../connection-advanced/oauth.md | 6 +++--- .../connection-advanced/permissions.md | 2 +- .../connection-basics/feedbacks.md | 2 +- .../connection-basics/input-field-types.md | 2 +- .../connection-basics/presets-1.x.md | 2 +- .../connection-basics/presets.md | 8 ++++---- .../module-development/local-modules.md | 8 ++++---- .../module-development/module-development-101.md | 4 ++-- .../module-lifecycle/module-packaging.md | 10 +++++----- .../module-lifecycle/renaming-your-module.md | 2 +- ...upgrading-a-module-built-for-companion-2.x.md | 16 ++++++++-------- for-developers/setting-up-WSL.md | 6 +++--- 20 files changed, 51 insertions(+), 51 deletions(-) diff --git a/for-developers/Satellite-API.md b/for-developers/Satellite-API.md index b6c10db..1c55b39 100644 --- a/for-developers/Satellite-API.md +++ b/for-developers/Satellite-API.md @@ -22,10 +22,10 @@ This lists what versions of Companion introduced support for each API version. ## API Spec -The server by default runs on port TCP 16622, but this will become configurable in the future. You should make sure to support alternate ports to allow for future compatibility as well as firewalls or router port forwarding. +The server by default runs on port TCP 16622, but this will become configurable in the future. You should make sure to support alternate ports to allow for future compatibility as well as firewalls or router port forwarding. As of Companion 3.5, it is also possible to use this protocol over websockets, with a default port of 16623. -Each message is presented as a line, with a `\n` or `\r\n` terminator. +Each message is presented as a line, with a `\n` or `\r\n` terminator. Messages follow the general format of `COMMAND-NAME ARG1=VAL1 ARG2=true ARG3="VAL3 with spaces"\n`. Key numbers are in the range of 0-31. @@ -35,7 +35,7 @@ Upon connection you will receive `BEGIN CompanionVersion=2.2.0-d9008309-3449 Api ## Messages to send -Upon receiving an unknown command, the server will respond with the format `ERROR MESSAGE="Unknown command: SOMETHING"` +Upon receiving an unknown command, the server will respond with the format `ERROR MESSAGE="Unknown command: SOMETHING"` Known commands will get either a success or error response like the following: - `COMMAND-NAME ERROR MESSAGE="Some text here"\n` @@ -51,7 +51,7 @@ Close the connection, removing all registered devices `PING payload` Check the server is alive, with an arbitrary payload -Responds with `PONG payload` +Responds with `PONG payload` You must call this at an interval, we recommend every 2 seconds, this is to ensure the connection does't get closed from being idle. ### Adding a satellite device @@ -76,7 +76,7 @@ Optional parameters: - `TEXT` - true/false whether you want to be streamed button text for display on the buttons (default false) - `TEXT_STYLE` - (added in v1.4.0) true/false whether you want to be streamed text style information for display on the buttons (default false) - `BRIGHTNESS` - (added in v1.7.0) true/false whether the device supporting changing brightness (default true) -- `VARIABLES` - (added in v1.7.0) a base64 encoded json array describing any input or output variables supported for this device +- `VARIABLES` - (added in v1.7.0) a base64 encoded json array describing any input or output variables supported for this device Each item in the array should be of the form: ``` { diff --git a/for-developers/core-development/development-flow.md b/for-developers/core-development/development-flow.md index 4373bfe..e84a304 100644 --- a/for-developers/core-development/development-flow.md +++ b/for-developers/core-development/development-flow.md @@ -94,7 +94,7 @@ To debug the back-end code you can: In VS Code, the simplest way to debug is to open a _Javascript Debug Terminal_ from the _Add Terminal_ pulldown menu (the '+' menu) and run either `yarn dev` (normal logging) or `yarn dev:debug` (voluminous reporting, debug-level: 'silly'). It is also possible to start these options from a menu using "_Debug: Debug npm script_" -:::tip +:::tip To include dev modules when running `yarn dev`, put the following in a file named `.env` in your top-level companion folder: ``` diff --git a/for-developers/git-workflows/versioning.md b/for-developers/git-workflows/versioning.md index a340969..f7a946d 100644 --- a/for-developers/git-workflows/versioning.md +++ b/for-developers/git-workflows/versioning.md @@ -27,7 +27,7 @@ Companion is not a monolithic application and different version numbers apply to We are following the standards given by semantic versioning, adopted for end-user applications. That means wherever semantic versioning relates to an API, we relate to end-user functionality. -- The major-version is counted up if there are breaking changes in the core of companion (on either a technical level, or a significant change in how users use the application). E.g.: stored database files will not be usable any more, APIs will not be usable any more +- The major-version is counted up if there are breaking changes in the core of companion (on either a technical level, or a significant change in how users use the application). E.g.: stored database files will not be usable any more, APIs will not be usable any more The major version is not a marketing instrument, we hope to avoid breaking changes as long as possible and so the major version should not change often. This is does not mean lack of innovation and actually less major versions are good. - The minor-version is counted up if functionality is added or changed in the core of companion. Added or changed functionality means that there is an intention to add or change functionality which the user can recognize. Typical examples are: a new item, better naming of an item, changed/better color of an item, changed/improved placement, changed behaviour like search giving grouped results instead ungrouped or results with scrollbars instead of no scrollbars. - The patch-version is counted up if there are changes which do not add or change functionality for the user or the change is that a broken functionality will be fixed. Typical examples are: refactoring code, bundling different versions of libraries or frameworks, fixing a bug without adding new functionality or changing the way it should have been working from the start. @@ -38,7 +38,7 @@ We are following the standards given by semantic versioning, adopted for end-use ### Version of Companion's APIs -Other applications or modules communicate with Companion by the use of application programming interfaces (APIs). It is the ultimate goal of API versioning to ensure compatibility. +Other applications or modules communicate with Companion by the use of application programming interfaces (APIs). It is the ultimate goal of API versioning to ensure compatibility. We are strictly following semantic versioning for our APIs. ### Version of Modules diff --git a/for-developers/module-development/api-changes/v1.12.md b/for-developers/module-development/api-changes/v1.12.md index 408ab89..56c9ffb 100644 --- a/for-developers/module-development/api-changes/v1.12.md +++ b/for-developers/module-development/api-changes/v1.12.md @@ -25,7 +25,7 @@ If possible it is advised to not use any of these permissions, as in the future :::tip -In the future we expect to make the filesystem permission more granular, with users being able to specify certain paths that your module is allowed to access. +In the future we expect to make the filesystem permission more granular, with users being able to specify certain paths that your module is allowed to access. We would recommend planning for this in your module implementation. ::: diff --git a/for-developers/module-development/api-changes/v1.5.md b/for-developers/module-development/api-changes/v1.5.md index 51ff325..e74401f 100644 --- a/for-developers/module-development/api-changes/v1.5.md +++ b/for-developers/module-development/api-changes/v1.5.md @@ -9,7 +9,7 @@ Boolean feedbacks now automatically get an 'inverted' property added by Companio :::tip -If you already have an option performing a similar job, we recommend using an upgrade script to move its value into our field and remove the option. +If you already have an option performing a similar job, we recommend using an upgrade script to move its value into our field and remove the option. Alternatively, you can opt out of our field, but be aware that users may have already set values that you should try to preserve ::: diff --git a/for-developers/module-development/api-changes/v1.8.md b/for-developers/module-development/api-changes/v1.8.md index 652e0bf..d470405 100644 --- a/for-developers/module-development/api-changes/v1.8.md +++ b/for-developers/module-development/api-changes/v1.8.md @@ -21,12 +21,12 @@ Companion has added a few variables under the `$(this:XX)` naming. (Since this r Due to the way the `parseVariablesInString` method works, Companion often doesn't know what button a string is being parsed for, so can't support variables scoped to a single button. -In order to support these, in your action/feedback callback, there is a second `context` parameter which holds an alternate `parseVariablesInString` implementation. This implementation is specific to that callback, so Companion knows what control it belongs to, and can handle the variables. +In order to support these, in your action/feedback callback, there is a second `context` parameter which holds an alternate `parseVariablesInString` implementation. This implementation is specific to that callback, so Companion knows what control it belongs to, and can handle the variables. Additionally, you can indicate that you are doing this and support these variables by setting the `useVariables` property to an object like `{ local: true }` to indicate this support. This allows us to show a hint to the user about this support, and suggest the available variables whilst they type. ## Shared UDP port listener for devices with hardcoded ports {#shared-udp} -A few devices have been found which are not cooperative when it comes to control, and expect to send all messages to a hardcoded UDP port. +A few devices have been found which are not cooperative when it comes to control, and expect to send all messages to a hardcoded UDP port. This makes it hard to support these, as by default only one connection can listen on a port at a time. To help with this, Companion offers some Shared UDP listener utils, where Companion will open and manage the port for you, and you can simply receive all messages sent to it. diff --git a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md index b944ffd..1499406 100644 --- a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md +++ b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md @@ -38,10 +38,10 @@ and in your `companion/manifest.json`: These two structures are linked by the common id, in the future this will allow us to automate device discovery further. -In the UI, this field will look like: +In the UI, this field will look like: ![image](../images/bonjour.png) -The 'Manual' option is always shown, and must be handled to allow users to manually specify an address for environments where Bonjour does not work. +The 'Manual' option is always shown, and must be handled to allow users to manually specify an address for environments where Bonjour does not work. This can be achieved with further config fields such as: ```js @@ -61,7 +61,7 @@ In your module code, the `bonjour_host` will have a value such as `10.0.0.1:8000 ### Writing your Bonjour Query -We currently support a subset of the possible query options. In all queries, the `type` and `protocol` must be set. +We currently support a subset of the possible query options. In all queries, the `type` and `protocol` must be set. If your device needs further filtering, this can be done by specifying any `txt` field values the entries must have. Since [API 1.10](../api-changes/v1.10.md) each entry in the manifest under `bonjourQueries` can be an array, to allow you to run multiple queries in parallel. This can be useful when supporting multiple models which use slightly different queries diff --git a/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md b/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md index f375c1a..b446a37 100644 --- a/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md +++ b/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md @@ -21,7 +21,7 @@ The process may involve a bit of work, but it is pretty straightforward. ### 1. Update feedback definitions -The feedback definitions need updating to the new style. +The feedback definitions need updating to the new style. From: ```javascript @@ -161,7 +161,7 @@ runEntrypoint(MyInstance, [myOtherUpgradeScript, upgradeToBooleanFeedbacks]) ``` This script will handle moving the options properties across to the style object for you. -It handles the most common cases of property naming, which may not match what your module does. +It handles the most common cases of property naming, which may not match what your module does. If this is the case, you can customise the behaviour by providing more details: ```js diff --git a/for-developers/module-development/connection-advanced/oauth.md b/for-developers/module-development/connection-advanced/oauth.md index 8732b46..1970dcf 100644 --- a/for-developers/module-development/connection-advanced/oauth.md +++ b/for-developers/module-development/connection-advanced/oauth.md @@ -5,7 +5,7 @@ sidebar_position: 3 description: How to set up Authentication with OAuth in the user configuration. --- -Some modules need to authenticate against an external service or API. +Some modules need to authenticate against an external service or API. Companion does not currently have native support for OAuth, so modules are required to do the flow manually. There are two key challenges to using OAuth with Companion: @@ -17,7 +17,7 @@ Described below is the current recommended way of supporting OAuth, but many exi ## Handling the OAuth callback / redirect URL -OAuth needs a stable redirect URL, as it needs to be provided to both Companion and in the application settings you are connecting to. +OAuth needs a stable redirect URL, as it needs to be provided to both Companion and in the application settings you are connecting to. To aid in this, a small redirector site has been created, which will help abstract this. This is hosted at `https://bitfocus.github.io/companion-oauth/callback`. @@ -79,7 +79,7 @@ async handleHttpRequest(request) { ## Opening the authentication URL -The user needs to open the authentication URL to start the OAuth process. +The user needs to open the authentication URL to start the OAuth process. As some users will be configuring their Companion remotely, you can't rely on being able to automatically open the url for them. Most modules currently will put the needed URL in a config field for the user to access, and also write it to the log. Some will also open it automatically. diff --git a/for-developers/module-development/connection-advanced/permissions.md b/for-developers/module-development/connection-advanced/permissions.md index ab77a09..e69fa11 100644 --- a/for-developers/module-development/connection-advanced/permissions.md +++ b/for-developers/module-development/connection-advanced/permissions.md @@ -5,7 +5,7 @@ sidebar_position: 10 description: Enable advanced runtime permissions for your module --- -Since [API 1.12](../api-changes/v1.12.md) modules are run with some restrictive permissions applied. The intention here is to limit some of the more dangerous abilities of the nodejs runtime, so that we can warn users about modules which require them. +Since [API 1.12](../api-changes/v1.12.md) modules are run with some restrictive permissions applied. The intention here is to limit some of the more dangerous abilities of the nodejs runtime, so that we can warn users about modules which require them. Think of it as similar to how your phone prompts you to accept a list of permissions when installing an app. To enable any of these, start by adding to the `runtime` object in your manifest: diff --git a/for-developers/module-development/connection-basics/feedbacks.md b/for-developers/module-development/connection-basics/feedbacks.md index bb27496..ab629af 100644 --- a/for-developers/module-development/connection-basics/feedbacks.md +++ b/for-developers/module-development/connection-basics/feedbacks.md @@ -167,7 +167,7 @@ Since [API v1.5](../api-changes/v1.5.md) (Companion 3.1), Companion provides bui If you wish to influence the auto-detection behaviour, you can do so by setting `showInvert: false` on a feedback. If this is an existing feedback, make sure to update any existing usages in an [upgrade scripts](./upgrade-scripts.md), to preserve existing behaviour for users. -If your feedback already provides a field to match a true or false state, we strongly advise removing it and replacing existing usage with the built-in invert property. +If your feedback already provides a field to match a true or false state, we strongly advise removing it and replacing existing usage with the built-in invert property. A helper function (`CreateUseBuiltinInvertForFeedbacksUpgradeScript`) is provided to generate an upgrade script for your module to convert an existing invert checkbox to the built-in system. It expects a parameter describe the feedbacks to process, and the name of the invert checkbox being replaced: ```js diff --git a/for-developers/module-development/connection-basics/input-field-types.md b/for-developers/module-development/connection-basics/input-field-types.md index d18c588..98cd074 100644 --- a/for-developers/module-development/connection-basics/input-field-types.md +++ b/for-developers/module-development/connection-basics/input-field-types.md @@ -5,7 +5,7 @@ sidebar_position: 18 description: Module input field types and definition details. --- -Companion has a standardised set of input fields usable across [action](./actions.md), [feedback](./feedbacks.md), or [user-config](./user-configuration.md) definitions. +Companion has a standardised set of input fields usable across [action](./actions.md), [feedback](./feedbacks.md), or [user-config](./user-configuration.md) definitions. There are some small differences in what is available where, documented here. ## Option types diff --git a/for-developers/module-development/connection-basics/presets-1.x.md b/for-developers/module-development/connection-basics/presets-1.x.md index 681a5e0..8915bed 100644 --- a/for-developers/module-development/connection-basics/presets-1.x.md +++ b/for-developers/module-development/connection-basics/presets-1.x.md @@ -6,7 +6,7 @@ description: Module presets definition details. --- :::warning -This describes how presets worked **before** the overhaul in the [API 2.0](../api-changes/v2.0.md). +This describes how presets worked **before** the overhaul in the [API 2.0](../api-changes/v2.0.md). If you are using the newer API, check the [new presets page](./presets.md) ::: diff --git a/for-developers/module-development/connection-basics/presets.md b/for-developers/module-development/connection-basics/presets.md index d13ec9f..75bc8bf 100644 --- a/for-developers/module-development/connection-basics/presets.md +++ b/for-developers/module-development/connection-basics/presets.md @@ -6,7 +6,7 @@ description: Module presets definition details. --- :::info -This describes the current state of presets in [API 2.0](../api-changes/v2.0.md). +This describes the current state of presets in [API 2.0](../api-changes/v2.0.md). If your module is using an older API version, you want the [old presets page](./presets-1.x.md). ::: @@ -79,7 +79,7 @@ this.setPresetDefinitions(structure, presets) ### Actions -The `steps` property is where the magic happens. This describes what the action will do when pressed. In the typical case a button will have a single step, which will give the behaviour of a normal button. +The `steps` property is where the magic happens. This describes what the action will do when pressed. In the typical case a button will have a single step, which will give the behaviour of a normal button. You can make a latching button by defining a second step which does something different. By default, each time the button is released it will shift to the next step, this can be disabled by setting `options: { stepAutoProgress: false }` for the preset. This likely isn't very useful right now, due to it not being possible to use internal actions in presets. You can add as many steps as you like, and build a button which runs through a whole cue list by simply pressing it. There are internal actions that a user can use to change the step manually. @@ -162,7 +162,7 @@ The feedbackId should match a feedback you have defined, and the options should ### Local Variables -You can also set a `localVariables` property to create some local variables on the button. Currently these are limited to be simple static values, intended to make it easier to use a value across the actions, feedbacks and style without repeating it. +You can also set a `localVariables` property to create some local variables on the button. Currently these are limited to be simple static values, intended to make it easier to use a value across the actions, feedbacks and style without repeating it. By doing this, it becomes much easier for the user to change it if needed. This also allows for better reusing one preset within the preset structure with [the templating groups](#template-groups). An example: @@ -287,7 +287,7 @@ If you were using the 'text' preset type previously, these groups will help you In a lot of modules, they have many channels/outputs/inputs or some other resource where presets are identical except for one number varying between them. -A simple matrix/video router module, will commonly produce a preset for each input+output combination, to quickly route each input to each output. This can often produce 100s or 1000s of presets which are almost identical. +A simple matrix/video router module, will commonly produce a preset for each input+output combination, to quickly route each input to each output. This can often produce 100s or 1000s of presets which are almost identical. In some cases, this has caused issues due to the size of the data produced being a performance drain and occasionally making the modules crash on lower powered machines Instead, groups in the new structure can be defined as 'template' groups. This templating, allows for overriding local variables you defined on the presets with different values. diff --git a/for-developers/module-development/local-modules.md b/for-developers/module-development/local-modules.md index 074eb3e..0af1040 100644 --- a/for-developers/module-development/local-modules.md +++ b/for-developers/module-development/local-modules.md @@ -12,9 +12,9 @@ Starting with Companion 3.0 you can develop, test and use your own module code w The structure is setup so that you can load multiple modules at the same time. A module folder is specified as described below. Inside of this folder should be one or more folders that use the following layouts, with each folder corresponding to a different module. -1. A git clone of a module from github +1. A git clone of a module from github This requires some additional setup, as the module will need to be prepared with a `yarn install`, and for some, a `yarn build`. -2. Packaged output +2. Packaged output This is a folder that contains a `companion/manifest.json`, `companion/HELP.md`, `package.json`, `main.js` (or another name), and possibly a few other files. No extra work is needed for this to be loaded @@ -32,7 +32,7 @@ Inside of this folder should be one or more folders that use the following layou - In the **Developer** section click on _**Select**_ to specify the directory where you have stored your developer modules. - Make sure **Enable Developer Modules** is switched on. You can now close the window -- Click on "Launch GUI" to open the Admin interface. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, be sure to choose the "dev" version in the configuration. +- Click on "Launch GUI" to open the Admin interface. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, be sure to choose the "dev" version in the configuration. If you don't see the developers module, please check the log and switch on debug, maybe the module has crashed. - You can replace a developers module or files within it while Companion is running. Companion will detect the change and restart only that module without affecting other modules. You can also force a module to reload by disabling and re-enabling a connection. @@ -51,7 +51,7 @@ the **Developer Module Path** is _**mydev**_ and not _mydev/module1_. - Find the developers module folder on your installation. This is often `/opt/companion-module-dev/`. - Check the section above on how to structure this folder - Run Companion. -- Open the Admin interface in your Browser. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, it will override the distributed version. +- Open the Admin interface in your Browser. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, it will override the distributed version. If you don't see the developers module, please check the log and switch on debug, maybe the module has crashed. ## Headless development diff --git a/for-developers/module-development/module-development-101.md b/for-developers/module-development/module-development-101.md index f24c324..7cf209e 100644 --- a/for-developers/module-development/module-development-101.md +++ b/for-developers/module-development/module-development-101.md @@ -62,8 +62,8 @@ See also our instructions for [debugging your module](./module-debugging.md) ## Test the module -In any case, your module should be tested throughout at different stages of its life. -You should check the compatibility to the Companion core, especially to different versions of the configuration fields. Some users may not have used Companion in a long time and their configuration file might look different than what you expect. +In any case, your module should be tested throughout at different stages of its life. +You should check the compatibility to the Companion core, especially to different versions of the configuration fields. Some users may not have used Companion in a long time and their configuration file might look different than what you expect. And last but not least you should check **all** your actions with **all** the options and feedbacks and whatever with the real device (as much as possible). Most bugs we find are typos, which would have easily been detected by complete testing. Also please don't rely solely on simulations where possible, often the real device reacts slightly differently than the simulator. ## Share your code diff --git a/for-developers/module-development/module-lifecycle/module-packaging.md b/for-developers/module-development/module-lifecycle/module-packaging.md index ae80f4f..8a22da7 100644 --- a/for-developers/module-development/module-lifecycle/module-packaging.md +++ b/for-developers/module-development/module-lifecycle/module-packaging.md @@ -56,7 +56,7 @@ Webpack has a few options for how `__dirname` behaves in packaged code. By defau ### Including extra data files :::tip -Since [API 1.12](../api-changes/v1.12.md), your module by default has read-only access to just your module folder, and not the whole filesystem. +Since [API 1.12](../api-changes/v1.12.md), your module by default has read-only access to just your module folder, and not the whole filesystem. You can [opt into more permissions](../connection-advanced/permissions.md) if you need it, but this will require permission from the user in the future. ::: @@ -70,8 +70,8 @@ module.exports = { } ``` -You can use any glob pattern to define files to be copied. -All files will be copied to the root folder of the package, which is the same folder where the packaged main script is in. Make sure that there are no name conflicts when copying files from different folders. +You can use any glob pattern to define files to be copied. +All files will be copied to the root folder of the package, which is the same folder where the packaged main script is in. Make sure that there are no name conflicts when copying files from different folders. Make sure you don't copy files you don't need, as these files will be included in the installation for all users of Companion. ### Using native dependencies @@ -83,7 +83,7 @@ Read more about [permissions](../connection-advanced/permissions.md). Native dependencies are not possible to bundle in the same way as js ones. So to support these requires a bit of extra work on your part. -It is not yet possible to use all native dependencies. We only support ones that publish prebuilt binaries as part of their npm package. +It is not yet possible to use all native dependencies. We only support ones that publish prebuilt binaries as part of their npm package. This means that some libraries are not possible to use. Reach out if you are affected by this, we would appreciate some input, and can work with you to find or fix a library to be compatible To support these modules, you should make one of two changes to your build-config.cjs, depending on how the library works. @@ -98,7 +98,7 @@ module.exports = { } ``` -If the library is using `node-gyp-build`, then there are a couple of options. +If the library is using `node-gyp-build`, then there are a couple of options. The preferred method is to set `useOriginalStructureDirname: true` in `build-config.cjs`. This changes the value of `__dirname` in your built module, and allows `node-gyp-build` to find its prebuilds. If you are not able to use `useOriginalStructureDirname: true`, then you can instead mark the dependency as an external: diff --git a/for-developers/module-development/module-lifecycle/renaming-your-module.md b/for-developers/module-development/module-lifecycle/renaming-your-module.md index 02ec6b5..5d1a78e 100644 --- a/for-developers/module-development/module-lifecycle/renaming-your-module.md +++ b/for-developers/module-development/module-lifecycle/renaming-your-module.md @@ -7,7 +7,7 @@ description: How to rename your module after having released it. Occasionally you will need to rename a module, perhaps for example, to make the name more inclusive as you add more devices, or the manufacturer releases a new device. -1. Ask in the module-development slack for approval on the new name +1. Ask in the module-development slack for approval on the new name This is so that we can be sure the new name conforms to our standard structure of `companion-module-manufacturer-product` (or `companion-module-manufacturer-protocol`). 2. Once approved, the team will be able to rename the GitHub repository for you. diff --git a/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md b/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md index 5169616..8f356d6 100644 --- a/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md +++ b/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md @@ -14,7 +14,7 @@ A majority of it will translate, but it will not be perfect match. You may want ## Background -In Companion 3.0, we rewrote the module-api from scratch. We chose to do this because the old api had grown very organically over 5 years, and was starting to show various issues. The main issues was modules were running in the main companion thread, and method signatures were assuming various calls to be synchronous, and modules being able to access various internals of companion (and some making concerningly large use of that ability). +In Companion 3.0, we rewrote the module-api from scratch. We chose to do this because the old api had grown very organically over 5 years, and was starting to show various issues. The main issues was modules were running in the main companion thread, and method signatures were assuming various calls to be synchronous, and modules being able to access various internals of companion (and some making concerningly large use of that ability). Rather than trying to quickly fix up the api, it was decided to rethink it entirely. The general shape of the api should be familiar, but many methods names have been changed, and the whole api is written to rely on promises a lot more when before either callbacks were abused or methods would be synchronous. @@ -206,7 +206,7 @@ Note: Even when there are no actions or feedbacks, you would need to put those o Note: Remember that the `rgb` and `rgbRev` methods no longer exist on your instance class. They have been renamed to `combineRgb` and `splitRgb` and should be imported from `'@companion-module/base'`. -The latch button mode has been replaced with a more flexible 'stepped' system. On each button, you can have as many steps as you wish, each with their own down/up/rotate actions. When releasing the button, it will by default automatically progress to the next step, or you can disable that and use an internal action to change the current step of a button. +The latch button mode has been replaced with a more flexible 'stepped' system. On each button, you can have as many steps as you wish, each with their own down/up/rotate actions. When releasing the button, it will by default automatically progress to the next step, or you can disable that and use an internal action to change the current step of a button. While is is wordier and more complex to make a latched button, this allows for much more complex flows, such as using another button as a 'shift' key, or having one 'go' button which runs the whole pre-programmed show. The `steps` property is an array of objects. Each object should be at a minimum `{ down: [], up: [] }` (`rotate_left` and `rotate_right` are also valid here). @@ -438,13 +438,13 @@ Inside of init, you are free to do things as you wish. But make sure that any me Tip: if you do a `this.checkFeedbacks()` inside of `init()`, you can remove that line -The method `config_fields` should be renamed to `getConfigFields`. -The method `updateConfig` should be renamed to `configUpdated`, it too is expected to return a Promise and should also be marked as async. +The method `config_fields` should be renamed to `getConfigFields`. +The method `updateConfig` should be renamed to `configUpdated`, it too is expected to return a Promise and should also be marked as async. The method `destroy` is expected to return a Promise and should also be marked as async. If you have a method called `action` or `feedback` still, make sure it has been migrated fully in the earlier steps, then remove it as it will no longer be called. -Some other methods provided by companion have been changed. +Some other methods provided by companion have been changed. Any where the name starts with an underscore must not be used as they are internal methods that will change without notice. - The static method `CreateConvertToBooleanFeedbackUpgradeScript` has been removed and can be imported from `@companion-module/base` instead @@ -500,8 +500,8 @@ During the build process of the releases your module package will be generated a Sometimes once built there are issues that prevent a package from running, so it is mandatory to test it before distributing it. In our experience, issues often occur when working with files from disk, or introducing a new dependency that doesn't play nice. Once you have done this once, if you are just changing some internal logic you probably don't need to repeat this unless you want to be sure. -You can build your module into this format with `yarn companion-module-build`. If this was successful, there should now be a `pkg` folder and a `pkg.tgz` file. These both contain the build version of your module! -If you create an empty file `DEBUG-PACKAGED` in your module folder, then companion will read the code from `pkg` instead. This will let you test it. +You can build your module into this format with `yarn companion-module-build`. If this was successful, there should now be a `pkg` folder and a `pkg.tgz` file. These both contain the build version of your module! +If you create an empty file `DEBUG-PACKAGED` in your module folder, then companion will read the code from `pkg` instead. This will let you test it. You probably don't need to do a very thorough test, as long as it starts and connects to your device and a couple of actions work it should be fine. Make sure to remove this `DEBUG-PACKAGED` file once you are done testing it, or next time you try to update your module it will keep loading the copy from `pkg`! @@ -510,7 +510,7 @@ If you encountered any issues in this process that you need help with, then have ### 15) Feedback -Have any thoughts/feedback on this process? Anything in the docs that should be improved? Do [let us know](https://github.com/bitfocus/companion-module-base/issues), we are interested in your feedback! +Have any thoughts/feedback on this process? Anything in the docs that should be improved? Do [let us know](https://github.com/bitfocus/companion-module-base/issues), we are interested in your feedback! We won't be able to cater to everything you dislike about the changes, as other modules are already using these new apis, but perhaps we can make the transition smoother? Have an idea of a new connection helper that would be beneficial to you? Or have some utility code that you are copying into multiple modules? We are interested to hear this. We are happy to add more to `@companion-module/base` if it will be useful to many modules and is unlikely to result in breaking changes. diff --git a/for-developers/setting-up-WSL.md b/for-developers/setting-up-WSL.md index ff03617..77d74bb 100644 --- a/for-developers/setting-up-WSL.md +++ b/for-developers/setting-up-WSL.md @@ -11,7 +11,7 @@ For other platforms see: [Initial Setup](setting-up-developer-environment.md) in Although it is possible to develop directly in Windows, there are occasions when you might want to use a Linux environment under Windows. The key is to use Windows' Subsystem for Linux (WSL). -First install Windows Subsystem for Linux version 2 (WSL2), +First install Windows Subsystem for Linux version 2 (WSL2), WSL is included with Windows but needs to be activated. Follow [Microsoft’s installation instructions](https://learn.microsoft.com/en-us/windows/wsl/setup/environment). Basically, open a command or powershell window and type: ```powershell @@ -22,7 +22,7 @@ After this completes, reboot your computer and WSL will automatically install th ## Install the basic development tools -Once this is done continue through Microsoft’s instructions, especially +Once this is done continue through Microsoft’s instructions, especially `sudo apt update && sudo apt upgrade`, as well as the instructions to: @@ -34,7 +34,7 @@ If you develop with Visual Studio Code, which we currently recommend, then you c You will need to install all the prerequisite tools on the WSL machine just like you would do on Linux, as described in the [Setting Up A Developer Environment](setting-up-developer-environment.md). -When you are running Companion from a VS Code terminal, VS Code will know the network ports and create automatic port forwards for you. That means although Companion runs on the virtual machine, you'll be able to access the admin page from your Windows host by accessing localhost or 127.0.0.1 and the used port. +When you are running Companion from a VS Code terminal, VS Code will know the network ports and create automatic port forwards for you. That means although Companion runs on the virtual machine, you'll be able to access the admin page from your Windows host by accessing localhost or 127.0.0.1 and the used port. That makes it quite convenient but you always have to remember that Companion runs on a virtual machine inside of your computer and that virtual machine has a different IP-address. When you want to access the API of software running on your Windows host, you can't use 127.0.0.1 like you would without WSL. 127.0.0.1 is the localhost of the WSL. WSL sets up a virtual network interface for you and to access your host OS, you have to use 172.28.96.1. Verify this using the command `ip route` in your Linux shell. ## Set Up Access to USB Ports From eec0aa33792fe85fb28abedcaf9a3228a2871798 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 16:04:41 -0800 Subject: [PATCH 03/12] fix admonitions spacing [Docusaurus recommends](https://docusaurus.io/docs/markdown-features/admonitions#usage-with-prettier) blank-lines after the opener (`:::note`) and before the closer (`:::`), in part, because prettier word-wraps these incorrectly... --- .../core-development/build-companion.md | 8 +++++++ .../core-development/development-flow.md | 15 ++++++++++++ .../git-workflows/github-workflow.md | 8 +++++++ .../git-workflows/installing-git.md | 4 ++++ .../module-development/api-changes/v2.0.md | 24 +++++++++++++++++++ .../connection-advanced/permissions.md | 4 ++++ .../connection-basics/actions.md | 10 ++++++++ .../connection-basics/feedbacks.md | 20 ++++++++++++++++ .../connection-basics/overview.md | 4 ++++ .../connection-basics/presets-1.x.md | 2 ++ .../connection-basics/presets.md | 8 +++++++ .../connection-basics/upgrade-scripts.md | 6 +++++ .../connection-basics/variables.md | 4 ++++ for-developers/module-development/home.md | 2 ++ .../module-development/module-debugging.md | 2 ++ .../module-lifecycle/module-packaging.md | 4 ++++ .../setting-up-developer-environment.md | 15 ++++++++++++ 17 files changed, 140 insertions(+) diff --git a/for-developers/core-development/build-companion.md b/for-developers/core-development/build-companion.md index 56fdad8..e84efd1 100644 --- a/for-developers/core-development/build-companion.md +++ b/for-developers/core-development/build-companion.md @@ -35,6 +35,7 @@ You can also start a "headless" run manually by running main.js from xxx-unpacke ``` :::info[Linux note] + To build Windows distributables from Linux systems (even WSL) you must install Wine first: ```bash @@ -43,9 +44,11 @@ sudo bash -c “dpkg --add-architecture i386 && apt-get update && apt-get instal ``` note: if your wine config gets corrupted, delete `~/.wine`. + ::: :::info[Windows note] + The very end of ‘yarn dist’ (signing) creates symlinks. By default, Windows restricts symlink creation, so this step will fail. You have three options to allow building Companion in Windows: 1. Run `yarn dist` in a shell with Administrator privileges. @@ -60,10 +63,15 @@ The very end of ‘yarn dist’ (signing) creates symlinks. By default, Windows ::: :::tip[Windows Tip] + Windows Antimalware Executable can slow down build times by 50-100%. You can improve performance by excluding certain folders: After cloning the companion repo and running `yarn install` the first time (see [Developing Core Companion](development-flow.md)) go to Windows Security > Virus and Threat Protection > Exclusions and add node_modules from your companion root. For completeness and a slight additional boost add: cache, dist, electron-output, shared-lib\dist, webui\build, and companion\dist. You may want/need to exclude these folders from backup apps too. + ::: :::danger[Raspberry Pi] + It is not recommended to run Companion on a Raspberry Pi with the desktop environment installed. + ::: + diff --git a/for-developers/core-development/development-flow.md b/for-developers/core-development/development-flow.md index e84a304..0b7d6e1 100644 --- a/for-developers/core-development/development-flow.md +++ b/for-developers/core-development/development-flow.md @@ -31,7 +31,9 @@ See topics below for running the launcher and docs in development mode. ### Getting Started: Cloning :::warning[Windows Note] + Be sure to [setup git line-endings behavior](../setting-up-developer-environment.md#3-install-and-setup-git) **before** cloning! + ::: Using your git client, you can clone Companion. To do it from a command line interface, change to the directory you want to contain the repo (the repo will be added as a subdirectoy) then: @@ -63,8 +65,10 @@ yarn dist:webui ``` :::tip[Windows Tip] + Windows Antimalware Executable can slow down install and build times by 50-100%. You can improve performance by excluding certain folders: After cloning the companion repo and running `yarn install` the first time (see above) go to Windows Security > Virus and Threat Protection > Exclusions and add node_modules from your companion root. For completeness and a slight additional boost add: cache, dist, electron-output, shared-lib\dist, webui\build, and companion\dist. You may want/need to exclude these folders from backup apps too. + ::: ### Updating: Fetch or Pull @@ -72,7 +76,9 @@ You may want/need to exclude these folders from backup apps too. Keep the up-to-date by fetching (`git fetch`) or pulling (`git pull`). See our pages [Git Crash Course](../git-workflows/git-crashcourse.md) and [GitHub Workflow](../git-workflows/github-workflow.md) if you need an introduction or refresher on these topics. :::tip + Consider using a graphical front-end such as SmartGit, or even the GitGUI program included with git, to visualize and simplify the process. + ::: ## Working with the back-end code @@ -95,6 +101,7 @@ To debug the back-end code you can: In VS Code, the simplest way to debug is to open a _Javascript Debug Terminal_ from the _Add Terminal_ pulldown menu (the '+' menu) and run either `yarn dev` (normal logging) or `yarn dev:debug` (voluminous reporting, debug-level: 'silly'). It is also possible to start these options from a menu using "_Debug: Debug npm script_" :::tip + To include dev modules when running `yarn dev`, put the following in a file named `.env` in your top-level companion folder: ``` @@ -104,6 +111,7 @@ COMPANION_DEV_MODULES= (Replace "\" with the actual path.) See [Setting a Dev Folder](../module-development/local-modules.md) for further details and options. + ::: ## Working with the (front-end) UI code @@ -124,11 +132,15 @@ This will launch the development version of the webui on a different port, typic ::: :::tip + You can open more than one terminal inside VS Code using the '+' menu, so in the first terminal run `yarn dev` and in the second one you can run `yarn dev:webui` + ::: :::note + `yarn dev:webui` is equivalent to running `yarn dev` from the webui folder, i.e. `cd webui; yarn dev` + ::: #### Debugging the webui in Visual Studio Code: @@ -195,5 +207,8 @@ yarn start **Developer documentation** (what you're reading now!) is maintained separately in the [Bitfocus website repo](https://github.com/bitfocus/website) under the folder _for-developers_. To contribute to the developer documentation, clone that repository, then use `yarn start` to get dynamic updates, as above. :::danger[warning] + Do not edit the _user-guide_, _versioned\*_ and _whats-new_ folders in the _**website**_ repo! They are automatically updated from the main companion repo. Edit the source for those folders in the _**companion**_ repo, as described above. + ::: + diff --git a/for-developers/git-workflows/github-workflow.md b/for-developers/git-workflows/github-workflow.md index cb25bfb..eff2897 100644 --- a/for-developers/git-workflows/github-workflow.md +++ b/for-developers/git-workflows/github-workflow.md @@ -19,13 +19,17 @@ The examples below use the core Companion repo, bitfocus/companion, for specific ::: :::note[Expert Note] + The following outline names the bitfocus remote "origin" and your remote fork "personal". This seems much clearer than the convention of naming the bitfocus repo "upstream" and your remote fork "origin" (which it is not!). The convention recommended here eliminates a step and also ensures that your pulls come from the Bitfocus repo. Many thanks to Brian Teeman for this and other suggestions. + ::: ## 1a. Clone Companion to a local repository :::warning[Windows Users!] + If you are cloning to a Windows computer be sure to [configure git line-endings as described here](installing-git.md#configure-git) _**before**_ cloning Companion. + ::: ```bash @@ -35,7 +39,9 @@ git clone https://github.com/bitfocus/companion.git (module developers: substitute the appropriate GitHub location.) :::note + The Bitfocus repository is read-only for most users. In the next step we will create a writeable "fork" of the Bitfocus repo that will be used for sending in proposed code changes (PRs) + ::: **updating**: Once your local repository has been established, use `git fetch` or `git pull` to keep it up-to-date. (Some GUI frontends can automate this part.) @@ -59,7 +65,9 @@ git remote add personal https://github.com//companion.git (In a GUI frontend you would select "Add Remote..." from a menu. SmartGit, for example, will automatically pick up the URL from your clipboard when you do this.) :::note + By default, the Bitfocus remote that you cloned above, was named "origin". So "origin" refers to Bitfocus (the "origin" of your clone) and "personal" refers to your fork on GitHub. + ::: ## 2. Create a new branch in your local repo diff --git a/for-developers/git-workflows/installing-git.md b/for-developers/git-workflows/installing-git.md index eec3f46..eaabbde 100644 --- a/for-developers/git-workflows/installing-git.md +++ b/for-developers/git-workflows/installing-git.md @@ -14,7 +14,9 @@ Install git following the instructions on [their website](https://git-scm.com/in Consider installing a graphical front-end to git: it can greatly simplify your git workflow. The following three popular options run on Windows, Mac and Linux. Many other GUI options are listed on [the git website](https://git-scm.com/tools/guis). :::note + You do not have to limit yourself to a single tool: because of the way Git works on your computer, you can use any or all of these simultaneously. Each tool has it's benefits, so you may find yourself quite naturally using each one to its strength. + ::: - The standard Git install, linked above, installs **Git GUI**, which though minimal is good at what it does, especially if you use the "_Visualize All Branch History_" viewer launched from the _Repository_ menu. On Windows the option to "Open Git Gui here" is added to the right-click menu for folders in the File Explorer. @@ -28,6 +30,7 @@ You do not have to limit yourself to a single tool: because of the way Git works ## Configure Git :::warning[Windows Note] + Companion’s `prettier` config requires `eol=lf`, but the system default (in C:/Program Files/Git/etc/gitconfig) may have set autocrlf to true during installation. In order for `git clone` to give you `lf` endings, i.e. before you have even downloaded the repository, this default needs to be overridden _**before you clone the companion repository**_. In a git bash window type: @@ -38,3 +41,4 @@ git config set --global core.eol lf ``` ::: + diff --git a/for-developers/module-development/api-changes/v2.0.md b/for-developers/module-development/api-changes/v2.0.md index 48099f5..3efb03d 100644 --- a/for-developers/module-development/api-changes/v2.0.md +++ b/for-developers/module-development/api-changes/v2.0.md @@ -5,9 +5,11 @@ description: 'Overview of API 2.0 breaking changes (expression parsing, presets --- :::warning + This version is still a draft and is not finalised yet Feel free to give this a read to prepare yourself for what is coming. It is not too late to give feedback! + ::: This is a major series of changes — the first breaking changes since Companion 3.0, over three years in the making. @@ -29,7 +31,9 @@ If your module is set to use the `node18` runtime in its manifest, it will need As part of dropping support for Node 18, this library is now written in the newer ESM syntax. For TypeScript users, update your `tsconfig` to use `"moduleResolution": "nodenext"`, or, if using our tsconfig presets, extend `@companion-module/tools/tsconfig/node22/recommended-esm`. :::tip + For most modules this will have no impact; you shouldn't need to change a JavaScript module. + ::: ### Remove `runEntrypoint` method @@ -117,7 +121,9 @@ We do this so you don't receive values you are unprepared to handle. However, so Some options don't make sense as expressions — for example, an option that chooses between `on`/`off`/`toggle`. Set `disableAutoExpression: true` on the field to disable expression support for that field. :::tip + You can set an `expressionDescription` to show guidance beneath the expression input field explaining what values are valid. + ::: If you use `subscribe` or `unsubscribe` on actions, consider setting the `optionsToMonitorForSubscribe` property to avoid unnecessary calls when unrelated options change. Some values may change multiple times per second and cause extra work for your module. @@ -136,13 +142,17 @@ Consider that the user will need to remember and write these. They will apprecia If you want to be really friendly, you could use `allowInvalidValues: true` and try to be tolerant of typos. :::tip + Now is the best time to address these, as you can assume that your upgrade script won't need to handle any expression values. If you do it later, you will need to handle expressions which are hiding the values being provided. + ::: ### Expression handling in upgrade scripts :::warning + This expression support introduces a breaking change for existing upgrade scripts. + ::: Unfortunately, expression support means your upgrade scripts must be prepared for any field to be an expression. Because we cannot know whether an upgrade script was written before or after expression support, we require all upgrade scripts to handle the new shape for all inputs. @@ -249,7 +259,9 @@ const result3 = FixupNumericOrVariablesValueToExpressions({ isExpression: false, ``` :::tip + Doing this cleanup now is easier than doing it later, since you don't yet need to handle stored `isExpression: true` values. + ::: ### Referencing expressions from `isVisibleExpression @@ -292,7 +304,9 @@ const presets = { ``` :::tip + Make sure to change the `type` property to `simple`. We intend to add additional types in a future release. Also remove the old `category` property. + ::: Using this object for `presets` lets you define a preset once and reference it in multiple places within the `structure` (see [Preset templating](#preset-templating)). @@ -323,7 +337,9 @@ This replaces the old `category` property that was previously defined on each pr If you were using the `text` definition type before, replace those entries with groups. :::tip + More group types are supported — see [Preset templating](#preset-templating) for details. + ::: ### Local variables in presets @@ -345,7 +361,9 @@ localVariables: [ This makes presets easier for users to edit by providing a single place to adjust values instead of editing multiple actions and feedbacks. :::tip + This pairs nicely with the `template` preset group, enabling simple templating within presets. + ::: ### Preset templating @@ -472,7 +490,9 @@ const act: CompanionActionDefinition<{ num: number }> = { In this example TypeScript knows that `event.options.num` is a number and that a value such as `event.options.other` does not exist. :::tip + You need to ensure that the generic and your option types match; we cannot do that automatically. + ::: Combined with the [Automatic expression parsing](#automatic-expression-parsing), this should ensure that the types you declare are what you actually receive and can tidy up a lot of logic. @@ -525,7 +545,9 @@ this.checkFeedbacks('my-feedback') ``` :::tip + We strongly recommend using `checkFeedbacks` with one or more arguments whenever possible, as it reduces the amount of work your module will do whenever a feedback changes + ::: Usages of `this.checkFeedbacksById(...)` are unaffected by this change, and remain valid. @@ -572,7 +594,9 @@ Since API 1.12 (Companion 4.0), it has been possible to define `isVisible` expre The old function-based `isVisible` approach is no longer supported and will be ignored. :::tip + When used in actions or feedbacks, expressions are only allowed to reference fields that cannot be an expression. See [Automatic expression parsing](#automatic-expression-parsing) for more details. + ::: #### Examples diff --git a/for-developers/module-development/connection-advanced/permissions.md b/for-developers/module-development/connection-advanced/permissions.md index e69fa11..53b6810 100644 --- a/for-developers/module-development/connection-advanced/permissions.md +++ b/for-developers/module-development/connection-advanced/permissions.md @@ -17,7 +17,9 @@ To enable any of these, start by adding to the `runtime` object in your manifest ``` :::tip + These permissions are applied during development too. However, when [the debugger](../module-debugging.md#attach-a-debugger) is enabled, the permissions are disabled. Make sure to test the module without the debugger enabled before publishing + ::: ## Worker threads @@ -63,8 +65,10 @@ If you need read access to more of the filesystem, or write access to the filesy ``` :::tip + In a future release of Companion, we intend to require the user to grant access to specific paths to each connection. View this as a request for more access, it may or may not be granted by the user. + ::: ## Insecure OpenSSL algorithms diff --git a/for-developers/module-development/connection-basics/actions.md b/for-developers/module-development/connection-basics/actions.md index 31fbb75..7acac79 100644 --- a/for-developers/module-development/connection-basics/actions.md +++ b/for-developers/module-development/connection-basics/actions.md @@ -14,7 +14,9 @@ This section explains how to define actions, provide options to the user, and re Your module defines the list of actions it supports by making a call to [`this.setActionDefinitions({ ...some actions here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setactiondefinitions). You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to update the list of actions exposed. :::warning + Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. + ::: ## Action definitions @@ -100,9 +102,11 @@ const actions = [ #### Using variables :::note + As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in textinput fields are now automatically parsed. As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to parse variables themselves, Companion does it for you based on the fields describing of the options. + ::: Between API v1.1 and API v1.14, a `context` object is passed as the second argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. @@ -168,7 +172,9 @@ Implementing the [learn option values](../connection-advanced/learn-action-feedb ### Result to Custom variable :::danger + This is an experimental idea, that may be removed without notice + ::: Some action executions return a value which may want to be used elsewhere in Companion. This could be written [to a custom variable](../connection-advanced/setting-custom-variables.md) @@ -176,7 +182,9 @@ Some action executions return a value which may want to be used elsewhere in Com ## TypeScript typings :::tip + This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself + ::: As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an `actions` property must be defined. @@ -229,7 +237,9 @@ const act: CompanionActionDefinition = { ``` :::tip + We can't enforce that the options array matches these types, you will have to do that yourself. + ::: These types will also propagate into [presets](./presets.md) diff --git a/for-developers/module-development/connection-basics/feedbacks.md b/for-developers/module-development/connection-basics/feedbacks.md index ab629af..766cf3c 100644 --- a/for-developers/module-development/connection-basics/feedbacks.md +++ b/for-developers/module-development/connection-basics/feedbacks.md @@ -14,19 +14,25 @@ This section explains how to define feedbacks, provide options to the user, and Your module defines the list of feedbacks it supports by making a call to [`this.setFeedbackDefinitions({ ...some feedbacks here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setfeedbackdefinitions). You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to update the list of feedbacks exposed. :::warning + Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. + ::: ## API calls: `checkFeedbacks(...)`, `checkAllFeedbacks()` & `checkFeedbacksById(...)` :::note + Starting with [API 2.0](../api-changes/v2.0.md), it is no longer possible to call `checkFeedbacks()` without any arguments. When you need to call this, you should instead use `checkAllFeedbacks()` + ::: You should tell Companion to re-run the callback of your feedbacks whenever the result is expected to change by calling `this.checkFeedbacks('your-feedback-id', 'another-feedback')`. :::tip + For modules with many options on feedbacks, you may want to make use of the [subscription flow](#subscribe--unsubscribe-flow) and `this.checkFeedbacksById('abc', 'def')`, to trigger smaller and more controlled invalidations. + ::: ## Feedback types @@ -58,7 +64,9 @@ Commonly, you will have some options on the feedback to let the user choose the They can also be used to return image pixel buffers, to show some custom content, although this is no longer recommended :::tip + In older versions of Companion, these were the only available type of feedback. We recommend that older modules should [update their feedbacks to boolean feedbacks](../connection-advanced/migrating-legacy-to-boolean-feedbacks.md) whenever possible. + ::: ## Feedback definitions @@ -121,7 +129,9 @@ Starting with API v1.1, feedback callbacks can be async or return a promise if y You should not be performing any network requests here, but it can be necessary when generating images or using other native code. :::tip + You must make sure to use a sensible timeout on any async execution, or your feedback can get stuck showing a stale value. + ::: #### Using variables @@ -129,9 +139,11 @@ You must make sure to use a sensible timeout on any async execution, or your fee Since API v1.1, it has been possible to use variables in feedback callbacks. This makes your feedbacks much more powerful as it lets the user build more complex interactions and systems. :::note + As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in textinput fields are now automatically parsed. As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to parse variables themselves, Companion does it for you based on the fields describing of the options. + ::: Between API v1.1 and API v1.14, a `context` object is passed as the second argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. @@ -227,8 +239,10 @@ Whenever the options of an feedback on a button is changed, only the callback wi With this, if you need to do any data loading, you should dispatch but not await this inside the callback, and trigger a reevaluation of the feedback (using either `this.checkFeedbacks()` or `this.checkFeedbacksById()`). :::tip + To help you decide if you need to perform any data loading, in each call to the `callback` you can now access the options provided to the previous call with `feedback.previousOptions`. With this you can check whether the options affecting the data loading have changed, and skip the loading process when it is not needed. + ::: It is also possible to force the callbacks for all your feedbacks to be re-executed, by calling `this.checkFeedbacks()` or `this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, to only run on a certain feedback type (eg `this.unsubscribeFeedbacks('set_source', 'set_source2')`). @@ -269,7 +283,9 @@ Whenever the options of an feedback on a button is changed, unsubscribe will be If the referenced variables change, the callback will be called without any calls to unsubscribe or subscribe. :::warning + There was a behaviour change in [API 1.13](../api-changes/v1.13.md). With all variables now being parsed by Companion when building the `options`, it no longer made sense to call unsubscribe and subscribe on every options change, so they will only be called when adding or removing the feedback + ::: It is also possible to force either unsubscribe or subscribe to be called for every feedback, by calling `this.subscribeFeedbacks()` or `this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, to only run on a certain feedback type (eg `this.unsubscribeFeedbacks('set_source', 'set_source2')`). @@ -283,7 +299,9 @@ Implementing the [learn option values](../connection-advanced/learn-action-feedb ## TypeScript typings :::tip + This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself + ::: As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an `feedbacks` property must be defined. @@ -337,7 +355,9 @@ const act: CompanionFeedbackDefinition = { ``` :::tip + We can't enforce that the options array matches these types, you will have to do that yourself. + ::: These types will also propagate into [presets](./presets.md) diff --git a/for-developers/module-development/connection-basics/overview.md b/for-developers/module-development/connection-basics/overview.md index 3d68105..a69e249 100644 --- a/for-developers/module-development/connection-basics/overview.md +++ b/for-developers/module-development/connection-basics/overview.md @@ -36,7 +36,9 @@ module.exports.UpgradeScripts = [...] // If you have any upgrade scripts ``` :::tip + In API 1.x, this was achieved by a call to `runEntrypoint(ModuleInstance, UpgradeScripts)`. This is no longer supported and will need to be updated + ::: ## Define the module class @@ -46,7 +48,9 @@ In API 1.x, this was achieved by a call to `runEntrypoint(ModuleInstance, Upgrad If you are not using TypeScript, you can skip this section :::tip + This has changed in [API 2.0](../api-changes/v2.0.md), before this it was a simpler `TConfig` that was generic for just your module config. + ::: The first step in creating a module is creating the module Instance class. If you are using the recommended [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts), then the module definition is in _src/main.ts_. diff --git a/for-developers/module-development/connection-basics/presets-1.x.md b/for-developers/module-development/connection-basics/presets-1.x.md index 8915bed..83c9eac 100644 --- a/for-developers/module-development/connection-basics/presets-1.x.md +++ b/for-developers/module-development/connection-basics/presets-1.x.md @@ -6,8 +6,10 @@ description: Module presets definition details. --- :::warning + This describes how presets worked **before** the overhaul in the [API 2.0](../api-changes/v2.0.md). If you are using the newer API, check the [new presets page](./presets.md) + ::: Presets are a description of ready-made buttons that will be presented to the user in the Presets tab on the Buttons page. diff --git a/for-developers/module-development/connection-basics/presets.md b/for-developers/module-development/connection-basics/presets.md index 75bc8bf..9561b45 100644 --- a/for-developers/module-development/connection-basics/presets.md +++ b/for-developers/module-development/connection-basics/presets.md @@ -6,8 +6,10 @@ description: Module presets definition details. --- :::info + This describes the current state of presets in [API 2.0](../api-changes/v2.0.md). If your module is using an older API version, you want the [old presets page](./presets-1.x.md). + ::: Presets are a description of ready-made buttons that will be presented to the user in the Presets tab on the Buttons page. @@ -18,8 +20,10 @@ The user can then drag-and-drop the preset onto the button-grid, to build out co In order to add presets to a module, you call `this.setPresetDefinitions(presetsStructure, presetsDefinitions)` much like how you define actions and feedbacks. However for presets you define your presets and a structure defining the layout separately. This allows for a lot more flexibility, and to reduce a lot of repetition :::tip + Make sure you call this after the `this.setActionDefinitions()` and `this.setFeedbackDefinitions()` calls. If you do it before, the variable replacement will be incomplete, and you will get errors in the logs about the missing action and feedback definitions. + ::: ## Preset types @@ -29,7 +33,9 @@ Currently there is one type of preset. We have plans to introduce more in a futu - [Simple Button Preset](https://bitfocus.github.io/companion-module-base/interfaces/CompanionSimplePresetDefinition.html) (`type: "simple"`) :::info + In API 1.x, there used to be a 'text' preset type too. That has been replaced with the new [structure](#preset-structure) object. + ::: ## Simple button preset definitions @@ -280,7 +286,9 @@ This allows for much more organisation of presets than before, without creating However, this is still a pretty manual and repetitive way of defining presets. For many, they could use some [templating](#template-groups) :::tip + If you were using the 'text' preset type previously, these groups will help you create the same effect and are just a bit more formalised. + ::: ### Template Groups diff --git a/for-developers/module-development/connection-basics/upgrade-scripts.md b/for-developers/module-development/connection-basics/upgrade-scripts.md index b85d15f..8ac4ffd 100644 --- a/for-developers/module-development/connection-basics/upgrade-scripts.md +++ b/for-developers/module-development/connection-basics/upgrade-scripts.md @@ -79,7 +79,9 @@ This may leave other pages of buttons broken as they will have been run through ## Writing an upgrade script :::tip + Each upgrade script will only get run once for each action and feedback, but it is good practice to write the scripts so that they can be executed multiple times. This will help you when testing your script, or if jumping between versions of companion. + ::: We recommend defining the functions in a dedicated `upgrades.ts` file, as they should not depend on your main class and this helps avoids files growing too long to be manageable. @@ -115,7 +117,9 @@ const UpgradeScripts = [ ``` :::warning + It is very important to not _remove_ an upgrade script once it has been defined. You can change old upgrade scripts if needed, but if the number of scripts gets reduced, then Companion will skip the next one you add for some users (it counts how many have been run) + ::: The script gets fed the bits of data you may need to do the upgrades. @@ -159,7 +163,9 @@ This looks something like: ``` :::warning + The options objects on these actions and feedbacks look _very_ different from how they do in the callback of your action or feedback. + ::: ### The return value diff --git a/for-developers/module-development/connection-basics/variables.md b/for-developers/module-development/connection-basics/variables.md index 44849b2..951d246 100644 --- a/for-developers/module-development/connection-basics/variables.md +++ b/for-developers/module-development/connection-basics/variables.md @@ -14,7 +14,9 @@ The basic workflow is to define your variables using `setVariableDefinitions()`, Your module should define the list of variables it exposes by making a call to `this.setVariableDefinitions([ ...some variables here... ])`. You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to change the list of variables exposed. :::warning + Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. + ::: ## Variable definitions @@ -63,7 +65,9 @@ Please try to batch variable updates whenever possible, as updating the values h ## TypeScript typings :::tip + This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself + ::: As part of the `InstanceTypes` generic argument passed to `InstanceBase`, a `variables` property must be defined. diff --git a/for-developers/module-development/home.md b/for-developers/module-development/home.md index c12f563..4e28ac0 100644 --- a/for-developers/module-development/home.md +++ b/for-developers/module-development/home.md @@ -22,9 +22,11 @@ You can develop modules against any standard release or beta build of Companion. Download and install a recent version from [the website](https://bitfocus.io/user/downloads) :::tip + Starting with Companion v4.0, the module release cycle has been decoupled from the Companion release cycle: The timing of module version releases are determined by the module developer independently of the Companion releases. We therefore recommend developing your module using the current stable version to ensure that users will be able to use your module right away instead of having to wait until the current beta is released. + ::: ## Set up the Development Folder diff --git a/for-developers/module-development/module-debugging.md b/for-developers/module-development/module-debugging.md index e863d74..a68984e 100644 --- a/for-developers/module-development/module-debugging.md +++ b/for-developers/module-development/module-debugging.md @@ -43,7 +43,9 @@ These messages will still show up in the module-specific log page and can be fil

:::note + Depending on buffering, several `console.log()` messages may be grouped together, so only the first will appear to have a timestamp. Use the API `this.log()` function described above, if seeing things reported in exactly the call order is important. + ::: ## Attach a debugger diff --git a/for-developers/module-development/module-lifecycle/module-packaging.md b/for-developers/module-development/module-lifecycle/module-packaging.md index 8a22da7..db10cbf 100644 --- a/for-developers/module-development/module-lifecycle/module-packaging.md +++ b/for-developers/module-development/module-lifecycle/module-packaging.md @@ -56,8 +56,10 @@ Webpack has a few options for how `__dirname` behaves in packaged code. By defau ### Including extra data files :::tip + Since [API 1.12](../api-changes/v1.12.md), your module by default has read-only access to just your module folder, and not the whole filesystem. You can [opt into more permissions](../connection-advanced/permissions.md) if you need it, but this will require permission from the user in the future. + ::: Sometimes it can be useful to store some extra data as text files, or other formats on disk. Once your module is packaged, it wont have access to any files, from the repository unless they are JavaScript which gets included in the bundle or the files are explicitly copied. You will need to do this to allow any `fs.readFile()` or similar calls to work. @@ -77,8 +79,10 @@ Make sure you don't copy files you don't need, as these files will be included i ### Using native dependencies :::tip + Since [API 1.12](../api-changes/v1.12.md), you have to mark in your manifest.json that you need to do this. In the future we will use this as information for the user. Read more about [permissions](../connection-advanced/permissions.md). + ::: Native dependencies are not possible to bundle in the same way as js ones. So to support these requires a bit of extra work on your part. diff --git a/for-developers/setting-up-developer-environment.md b/for-developers/setting-up-developer-environment.md index 778dcbb..4d17bec 100644 --- a/for-developers/setting-up-developer-environment.md +++ b/for-developers/setting-up-developer-environment.md @@ -12,8 +12,10 @@ Companion is written in Javascript/TypeScript and uses the [Node.js](https://nod Companion, Javascript and Node.js are platform independent, so you can develop on Windows, macOS or Linux and the code you write will be able to run on all three platforms. :::note + For module development you may be able to skip step 5, below, "Enabling USB on Unix". Instead simply install Companion according to the instructions in the getting started guide. + ::: ## 1. Install Node.js manager (fnm) @@ -23,11 +25,15 @@ We strongly recommend using the [fnm](https://github.com/Schniz/fnm#installation ### Installing fnm on Windows :::note + If you want to run in Linux Subsystem for Windows (aka WSL), please follow the [WSL Instructions page](setting-up-WSL.md) and then follow the instructions, below, in the [Linux section, below](#installing-fnm-on-linux-and-macos). + ::: :::tip + If PowerShell complains about unsigned apps, go to Settings, search for "developer settings" and enable "Change execution policy to allow local PowerShell scripts to run without signing". Alternatively, in a PowerShell with elevated permissions run: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` + ::: If you are new to code development on Windows, the built-in `winget` command is probably the simplest way to install fnm. (Other popular package managers such as Chocolatey and Scoop work similarly.) @@ -60,6 +66,7 @@ curl -fsSL https://fnm.vercel.app/install | bash ``` :::note + The install script requires unzip to be installed on your system. If it isn't, install it by typing: ``` @@ -93,9 +100,11 @@ corepack enable (Note: `corepack enable` may not be needed in Windows if using PowerShell with the setup described above.) :::note + Some older modules uses node v18 instead of v22, but are encouraged to update to v22. Sometimes updating the node version can introduce new bugs, but staying on older versions makes development harder as tools drop support for those versions. At some point, Companion will require modules to be node v22 (or perhaps a newer version). With fnm you can install both v18 and v22 and quickly switch between versions as needed. fnm can be setup to do this automatically with the `--use-on-cd` switch (as recommended in the [Windows section](#installing-fnm-on-windows) above), or you can switch it manually with a command like `fnm use 22`. See the [fnm config](https://github.com/Schniz/fnm/blob/master/docs/configuration.md) docs for more information on `--use-on-cd` and the related `--resolve-engines` options. + ::: :::warning @@ -111,6 +120,7 @@ yarn globally and are having problems, consider removing the global install. See the [instructions for installing Git here](./git-workflows/installing-git.md). :::info[Windows Note] + As per [the windows note here](./git-workflows/installing-git.md#configure-git): In order for `git clone` to give you `lf` endings, this default needs to be overridden _**before you clone the companion repository**_. In a git bash window type: @@ -134,9 +144,14 @@ To edit the source code or write new code you can use any text editor you like, If you have no prior experience, we recommend the [Visual Studio Code](https://code.visualstudio.com/) editor (VS Code). :::tip + We recommend installing the _ESLint_, _prettier_ and _typos_ plugins for VS Code. + ::: :::note[Linux Note] + If you want a simple windowing text-editor in Linux, you can try gedit. Install it with `sudo apt install gedit` + ::: + From 35c9cfc0977ebd1054a5597928f9798c8cf5b763 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 21:55:14 -0800 Subject: [PATCH 04/12] fix: reflow all long lines run ``` yarn prettier --prose-wrap always --print-width 80 --parser mdx --write "**/*.md" ``` --- for-developers/Satellite-API.md | 164 ++-- .../core-development/build-companion.md | 50 +- .../core-development/development-flow.md | 146 +++- .../core-development/intro-to-core.md | 11 +- .../git-workflows/git-crashcourse.md | 110 ++- .../git-workflows/github-workflow.md | 93 ++- .../git-workflows/installing-git.md | 55 +- for-developers/git-workflows/versioning.md | 87 ++- for-developers/index.md | 18 +- for-developers/linking-to-companion.md | 23 +- .../making-a-release-of-companion.md | 49 +- .../module-development/api-changes/index.md | 4 +- .../module-development/api-changes/v1.10.md | 19 +- .../module-development/api-changes/v1.12.md | 23 +- .../module-development/api-changes/v1.13.md | 48 +- .../module-development/api-changes/v1.14.md | 22 +- .../module-development/api-changes/v1.5.md | 12 +- .../module-development/api-changes/v1.7.md | 6 +- .../module-development/api-changes/v1.8.md | 36 +- .../module-development/api-changes/v2.0.md | 349 ++++++--- .../bonjour-device-discovery.md | 39 +- .../connection-advanced/http-handler.md | 33 +- .../learn-action-feedback-values.md | 41 +- .../migrating-legacy-to-boolean-feedbacks.md | 41 +- .../connection-advanced/oauth.md | 39 +- .../connection-advanced/permissions.md | 33 +- .../setting-custom-variables.md | 30 +- .../connection-basics/actions.md | 145 +++- .../connection-basics/connecting.md | 40 +- .../connection-basics/feedbacks.md | 238 ++++-- .../connection-basics/index.md | 3 +- .../connection-basics/input-field-types.md | 61 +- .../connection-basics/logging.md | 26 +- .../connection-basics/overview.md | 113 ++- .../connection-basics/presets-1.x.md | 91 ++- .../connection-basics/presets.md | 157 ++-- .../connection-basics/upgrade-scripts.md | 94 ++- .../connection-basics/user-configuration.md | 80 +- .../connection-basics/variables.md | 52 +- for-developers/module-development/home.md | 134 +++- for-developers/module-development/index.md | 8 +- .../module-development/local-modules.md | 74 +- .../module-development/module-debugging.md | 61 +- .../module-development-101.md | 113 ++- .../companion-module-library.md | 69 +- .../module-lifecycle/index.md | 6 +- .../module-lifecycle/module-packaging.md | 152 +++- .../module-lifecycle/releasing-your-module.md | 49 +- .../module-lifecycle/renaming-your-module.md | 24 +- ...ustom-version-of-@companion-module-base.md | 38 +- .../module-lifecycle/updating-nodejs.md | 41 +- ...rading-a-module-built-for-companion-2.x.md | 723 +++++++++++++----- .../module-setup/code-quality.md | 56 +- .../module-setup/file-structure.md | 121 ++- .../module-development/module-setup/index.md | 3 +- .../module-setup/manifest.json.md | 54 +- .../module-setup/typescript-config.md | 17 +- .../module-setup/unit-testing.md | 12 +- for-developers/setting-up-WSL.md | 95 ++- .../setting-up-developer-environment.md | 101 ++- 60 files changed, 3354 insertions(+), 1278 deletions(-) diff --git a/for-developers/Satellite-API.md b/for-developers/Satellite-API.md index 1c55b39..a04ec3b 100644 --- a/for-developers/Satellite-API.md +++ b/for-developers/Satellite-API.md @@ -4,9 +4,13 @@ sidebar_label: Satellite API sidebar_position: 90 --- -It is possible to remotely connect a 'Stream Deck' to companion so that it appears as its own device and follows the paging model. This is different from how the OSC/TCP/UDP servers operate. +It is possible to remotely connect a 'Stream Deck' to companion so that it +appears as its own device and follows the paging model. This is different from +how the OSC/TCP/UDP servers operate. -This page documents the protocol. The intention is to only ever add non-breaking functionality to this API, and to keep this document updated with new functionality as it is added. +This page documents the protocol. The intention is to only ever add non-breaking +functionality to this API, and to keep this document updated with new +functionality as it is added. ## Companion version support @@ -22,21 +26,34 @@ This lists what versions of Companion introduced support for each API version. ## API Spec -The server by default runs on port TCP 16622, but this will become configurable in the future. You should make sure to support alternate ports to allow for future compatibility as well as firewalls or router port forwarding. -As of Companion 3.5, it is also possible to use this protocol over websockets, with a default port of 16623. - -Each message is presented as a line, with a `\n` or `\r\n` terminator. -Messages follow the general format of `COMMAND-NAME ARG1=VAL1 ARG2=true ARG3="VAL3 with spaces"\n`. -Key numbers are in the range of 0-31. - -Note: You can send boolean values can as both true/false and 0/1, you will always receive them as 0/1 - -Upon connection you will receive `BEGIN CompanionVersion=2.2.0-d9008309-3449 ApiVersion=1.0.0` stating the build of companion you are connected to. The `CompanionVersion` field should not be relied on to be meaningful to your application, but can be presented as information to the user, or to aid debugging. You should use the `ApiVersion` field to check compatibility with companion. The number followers [semver](https://semver.org/) for versioning. We hope to keep breaking changes to a minimum, and will do so only when necessary. +The server by default runs on port TCP 16622, but this will become configurable +in the future. You should make sure to support alternate ports to allow for +future compatibility as well as firewalls or router port forwarding. As of +Companion 3.5, it is also possible to use this protocol over websockets, with a +default port of 16623. + +Each message is presented as a line, with a `\n` or `\r\n` terminator. Messages +follow the general format of +`COMMAND-NAME ARG1=VAL1 ARG2=true ARG3="VAL3 with spaces"\n`. Key numbers are in +the range of 0-31. + +Note: You can send boolean values can as both true/false and 0/1, you will +always receive them as 0/1 + +Upon connection you will receive +`BEGIN CompanionVersion=2.2.0-d9008309-3449 ApiVersion=1.0.0` stating the build +of companion you are connected to. The `CompanionVersion` field should not be +relied on to be meaningful to your application, but can be presented as +information to the user, or to aid debugging. You should use the `ApiVersion` +field to check compatibility with companion. The number followers +[semver](https://semver.org/) for versioning. We hope to keep breaking changes +to a minimum, and will do so only when necessary. ## Messages to send -Upon receiving an unknown command, the server will respond with the format `ERROR MESSAGE="Unknown command: SOMETHING"` -Known commands will get either a success or error response like the following: +Upon receiving an unknown command, the server will respond with the format +`ERROR MESSAGE="Unknown command: SOMETHING"` Known commands will get either a +success or error response like the following: - `COMMAND-NAME ERROR MESSAGE="Some text here"\n` - `COMMAND-NAME OK\n` @@ -44,40 +61,55 @@ Known commands will get either a success or error response like the following: ### Close connection -`QUIT` -Close the connection, removing all registered devices +`QUIT` - Close the connection, removing all registered devices ### Ping/pong -`PING payload` -Check the server is alive, with an arbitrary payload -Responds with `PONG payload` -You must call this at an interval, we recommend every 2 seconds, this is to ensure the connection does't get closed from being idle. +`PING payload` - Check the server is alive, with an arbitrary payload Responds +with `PONG payload` You must call this at an interval, we recommend every 2 +seconds, this is to ensure the connection does't get closed from being idle. ### Adding a satellite device `ADD-DEVICE DEVICEID=00000 PRODUCT_NAME="Satellite Streamdeck"` -- `DEVICEID` should be a unique identifier for the hardware device. such as a serial number, or mac address. This should be in the format `streamdeck:12345` to both ensure there aren't collisions between device types, and make the id a bit more meaningful. -- `PRODUCT_NAME` is the name of the product to show in the Surfaces table in the UI +- `DEVICEID` should be a unique identifier for the hardware device. such as a + serial number, or mac address. This should be in the format `streamdeck:12345` + to both ensure there aren't collisions between device types, and make the id a + bit more meaningful. +- `PRODUCT_NAME` is the name of the product to show in the Surfaces table in the + UI Optional parameters: -- `KEYS_TOTAL` - number of keys the device has. (default 32) Valid values varies depending on API Version: +- `KEYS_TOTAL` - number of keys the device has. (default 32) Valid values varies + depending on API Version: - Since 1.5.1, this can be any integer value >= 1 - Before 1.5.1, must be in the range 1-32 -- `KEYS_PER_ROW` - number of keys per row. (default 8) Valid values varies depending on API Version: +- `KEYS_PER_ROW` - number of keys per row. (default 8) Valid values varies + depending on API Version: - Since 1.5.1, this can be any integer value >= 1 - Before 1.5.1, must be in the range 1-8 - `BITMAPS` - This varies depending on API Version: - - Since 1.5.0, this is a number specifying the desired size of the bitmaps. If 0 or false, then bitmaps will not be streamed. If 1 or true, they will be 72px (default 72) - - Before 1.5.0, this is true/false whether you want to be streamed bitmaps for display on the buttons (default true) -- `COLORS` - Since 1.6 true/false/'hex'/'rgb', before 1.6 true/false whether you want to be streamed colors for display on the buttons and in which format (default false). If you specify true or 'hex', you'll get color readouts in hexadecimal notation, if you specify 'rgb', you'll get color readouts in css rgb notation without spaces. -- `TEXT` - true/false whether you want to be streamed button text for display on the buttons (default false) -- `TEXT_STYLE` - (added in v1.4.0) true/false whether you want to be streamed text style information for display on the buttons (default false) -- `BRIGHTNESS` - (added in v1.7.0) true/false whether the device supporting changing brightness (default true) -- `VARIABLES` - (added in v1.7.0) a base64 encoded json array describing any input or output variables supported for this device - Each item in the array should be of the form: + - Since 1.5.0, this is a number specifying the desired size of the bitmaps. If + 0 or false, then bitmaps will not be streamed. If 1 or true, they will be + 72px (default 72) + - Before 1.5.0, this is true/false whether you want to be streamed bitmaps for + display on the buttons (default true) +- `COLORS` - Since 1.6 true/false/'hex'/'rgb', before 1.6 true/false whether you + want to be streamed colors for display on the buttons and in which format + (default false). If you specify true or 'hex', you'll get color readouts in + hexadecimal notation, if you specify 'rgb', you'll get color readouts in css + rgb notation without spaces. +- `TEXT` - true/false whether you want to be streamed button text for display on + the buttons (default false) +- `TEXT_STYLE` - (added in v1.4.0) true/false whether you want to be streamed + text style information for display on the buttons (default false) +- `BRIGHTNESS` - (added in v1.7.0) true/false whether the device supporting + changing brightness (default true) +- `VARIABLES` - (added in v1.7.0) a base64 encoded json array describing any + input or output variables supported for this device Each item in the array + should be of the form: ``` { "id": "some-id", // This is the identifier used when sending/receiving a value for the variable @@ -86,7 +118,11 @@ Optional parameters: "description": "Something longer about it. eg Supports values in range 0-100", // A longer user facing description of this variable } ``` -- `PINCODE_LOCK` - (added in v1.8.0) you can set to indicate that you will handle display of the pincode locked state. set to `FULL` to indicate that you will handle display and input or to `PARTIAL` to indicate that you will handle display and the user will not be able to input a pincode. (Partial mode has no difference in behaviour currently, but we will utilise it in the future) +- `PINCODE_LOCK` - (added in v1.8.0) you can set to indicate that you will + handle display of the pincode locked state. set to `FULL` to indicate that you + will handle display and input or to `PARTIAL` to indicate that you will handle + display and the user will not be able to input a pincode. (Partial mode has no + difference in behaviour currently, but we will utilise it in the future) ### Removing a satellite device @@ -99,17 +135,22 @@ Optional parameters: `KEY-PRESS DEVICEID=00000 KEY=0 PRESSED=true` - `DEVICEID` the unique identifier used to add the device -- `KEY` number of the key which is pressed/released. Since v1.6 this can be either a legacy key number or the local row/column starting at top left with `0/0` and counting up towards bottom/right +- `KEY` number of the key which is pressed/released. Since v1.6 this can be + either a legacy key number or the local row/column starting at top left with + `0/0` and counting up towards bottom/right - `PRESSED` true/false whether the key is pressed ### Rotating an encoder (Since v1.3.0) -Note: there is a checkbox to enable this per bank inside Companion, allowing users to define the actions to execute +Note: there is a checkbox to enable this per bank inside Companion, allowing +users to define the actions to execute `KEY-ROTATE DEVICEID=00000 KEY=0 DIRECTION=1` - `DEVICEID` the unique identifier used to add the device -- `KEY` number of the key/encoder which is rotated. Since v1.6 this can be either a legacy key number or the local row/column starting at top left with `0/0` and counting up towards bottom/right +- `KEY` number of the key/encoder which is rotated. Since v1.6 this can be + either a legacy key number or the local row/column starting at top left with + `0/0` and counting up towards bottom/right - `DIRECTION` direction of the rotation. 1 for right, -1 for left ### Updating a variable (Since v1.7.0) @@ -120,28 +161,32 @@ This can be used when input variables are defined as part of `ADD-DEVICE`. - `DEVICEID` the unique identifier used to add the device - `VARIABLE` the id of the variable being updated -- `VALUE` the value of the variable, base64 encoded. The encoding is so that special characters and newlines don't have to be escaped, avoiding a wide range of easy to trigger bugs. +- `VALUE` the value of the variable, base64 encoded. The encoding is so that + special characters and newlines don't have to be escaped, avoiding a wide + range of easy to trigger bugs. ### Pincode key press (Since v1.8.0) -When handling the pincode locked state yourself, report a pincode key was pressed +When handling the pincode locked state yourself, report a pincode key was +pressed `PINCODE-KEY DEVICEID=00000 KEY=1` - `DEVICEID` the unique identifier used to add the device - `KEY` the value of the pressed key (0-9) -Note: depending on your surface, this may not translate directly to a button press. +Note: depending on your surface, this may not translate directly to a button +press. ## Messages to receive -No responses are expected to these unless stated below, and to do so will result in an error. +No responses are expected to these unless stated below, and to do so will result +in an error. ### Ping/pong -`PING payload` -The server is checking you are still alive, with an arbitrary payload -You must respond with `PONG payload` +`PING payload` - The server is checking you are still alive, with an arbitrary +payload You must respond with `PONG payload` ### State change for key @@ -149,17 +194,27 @@ You must respond with `PONG payload` - `DEVICEID` the unique identifier of the device - `KEY` number of the key which the pixel buffer is for -- `TYPE` type of the key. (added in v1.1.0) Either `BUTTON`, `PAGEUP`, `PAGEDOWN` or `PAGENUM` +- `TYPE` type of the key. (added in v1.1.0) Either `BUTTON`, `PAGEUP`, + `PAGEDOWN` or `PAGENUM` Optional parameters: -- `BITMAP` base64 encoded pixel data. This is only sent for devices which were added where `BITMAPS` is enabled. Resolution follows the size defined by the `BITMAPS` (if using a suitable API version). Currently encoded as 8-bit RGB (this may be configurable in the future). -- `COLOR` hex or css encoded 8-bit RGB color for the key background. This is only sent for devices which were added where `COLORS` was true -- `TEXTCOLOR` hex or css encoded 8-bit RGB color for the key text. This is only sent for devices which were added where `COLORS` was true (added in v1.6) -- `TEXT` base64 encoded text as should be displayed on the key. This is only sent for devices which were added where `TEXT` was true -- `FONT_SIZE` numeric size that should be used when displaying the text on the key. This is only sent for devices which were added where `TEXT_STYLE` was true (added in v1.4.0) - -Note: expect more parameters to be added to this message over time. Some could increase the frequency of the message being received. +- `BITMAP` base64 encoded pixel data. This is only sent for devices which were + added where `BITMAPS` is enabled. Resolution follows the size defined by the + `BITMAPS` (if using a suitable API version). Currently encoded as 8-bit RGB + (this may be configurable in the future). +- `COLOR` hex or css encoded 8-bit RGB color for the key background. This is + only sent for devices which were added where `COLORS` was true +- `TEXTCOLOR` hex or css encoded 8-bit RGB color for the key text. This is only + sent for devices which were added where `COLORS` was true (added in v1.6) +- `TEXT` base64 encoded text as should be displayed on the key. This is only + sent for devices which were added where `TEXT` was true +- `FONT_SIZE` numeric size that should be used when displaying the text on the + key. This is only sent for devices which were added where `TEXT_STYLE` was + true (added in v1.4.0) + +Note: expect more parameters to be added to this message over time. Some could +increase the frequency of the message being received. ### Reset all keys to black @@ -182,7 +237,9 @@ This can be received when output variables are defined as part of `ADD-DEVICE`. - `DEVICEID` the unique identifier used to add the device - `VARIABLE` the id of the variable being updated -- `VALUE` the value of the variable, base64 encoded. The encoding is so that special characters and newlines don't have to be escaped, avoiding a wide range of easy to trigger bugs. +- `VALUE` the value of the variable, base64 encoded. The encoding is so that + special characters and newlines don't have to be escaped, avoiding a wide + range of easy to trigger bugs. ### Locked state update (Since v1.8.0) @@ -194,4 +251,5 @@ This can be received when `PINCODE_LOCK` was specified when adding the device - `LOCKED` whether the surface is locked - `CHARACTER_COUNT` how many characters have been entered for the pincode -Between this reporting `LOCKED=true` and `LOCKED=false`, you will not receive any other drawing messages, and any input messages you send will be ignored. +Between this reporting `LOCKED=true` and `LOCKED=false`, you will not receive +any other drawing messages, and any input messages you send will be ignored. diff --git a/for-developers/core-development/build-companion.md b/for-developers/core-development/build-companion.md index e84efd1..eb05d2c 100644 --- a/for-developers/core-development/build-companion.md +++ b/for-developers/core-development/build-companion.md @@ -5,7 +5,8 @@ sidebar_position: 12 description: Sharing your modified Companion with others --- -The Companion repo allows you to build a distributable binary from sources by running +The Companion repo allows you to build a distributable binary from sources by +running ```bash yarn dist @@ -19,16 +20,23 @@ You can also cross-build for a specific platform using one of the following: - macOS intel: `yarn macdist` - macOS Apple silicon: `yarn macarmdist` -The build will be added to a sub-directory of _electron-output/_ named _xxx_-unpacked. For example _electron-output/linux-unpacked_ or _electron-output/win-unpacked_. +The build will be added to a sub-directory of _electron-output/_ named +_xxx_-unpacked. For example _electron-output/linux-unpacked_ or +_electron-output/win-unpacked_. -There you will find a binary to run a Headed build (a system with a monitor, keyboard, and mouse). -On Windows it is named _Companion.exe_ on linux it is named _companion-launcher_ +There you will find a binary to run a Headed build (a system with a monitor, +keyboard, and mouse). On Windows it is named _Companion.exe_ on linux it is +named _companion-launcher_ -Windows builds also include an installer program named _companion-win64.exe_ in _electron-output/_ (not _electron-output/win-unpacked_!), which can be distributed independently of the "unpacked" contents. +Windows builds also include an installer program named _companion-win64.exe_ in +_electron-output/_ (not _electron-output/win-unpacked_!), which can be +distributed independently of the "unpacked" contents. -Linux builds include a shell script to run headless named _companion_headless.sh_ +Linux builds include a shell script to run headless named +_companion_headless.sh_ -You can also start a "headless" run manually by running main.js from xxx-unpacked/resources, i.e.: +You can also start a "headless" run manually by running main.js from +xxx-unpacked/resources, i.e.: ```bash ./node-runtimes/main/bin/node main.js @@ -36,7 +44,8 @@ You can also start a "headless" run manually by running main.js from xxx-unpacke :::info[Linux note] -To build Windows distributables from Linux systems (even WSL) you must install Wine first: +To build Windows distributables from Linux systems (even WSL) you must install +Wine first: ```bash sudo apt install wine @@ -49,14 +58,19 @@ note: if your wine config gets corrupted, delete `~/.wine`. :::info[Windows note] -The very end of ‘yarn dist’ (signing) creates symlinks. By default, Windows restricts symlink creation, so this step will fail. You have three options to allow building Companion in Windows: +The very end of ‘yarn dist’ (signing) creates symlinks. By default, Windows +restricts symlink creation, so this step will fail. You have three options to +allow building Companion in Windows: 1. Run `yarn dist` in a shell with Administrator privileges. -2. Turn on Developer Mode in Windows Settings. (Open Settings and search for "developer"): +2. Turn on Developer Mode in Windows Settings. (Open Settings and search for + "developer"): ![image](images/developers-setting.png) -3. Set a local policy in the “Local Security Policy” editor: Security Settings > Local Policies > User Rights Assignment: Create symbolic links, to allow yourself to create symlinks: +3. Set a local policy in the “Local Security Policy” editor: Security Settings > + Local Policies > User Rights Assignment: Create symbolic links, to allow + yourself to create symlinks: ![image](images/set-symlink-permission.png) @@ -64,14 +78,20 @@ The very end of ‘yarn dist’ (signing) creates symlinks. By default, Windows :::tip[Windows Tip] -Windows Antimalware Executable can slow down build times by 50-100%. You can improve performance by excluding certain folders: After cloning the companion repo and running `yarn install` the first time (see [Developing Core Companion](development-flow.md)) go to Windows Security > Virus and Threat Protection > Exclusions and add node_modules from your companion root. For completeness and a slight additional boost add: cache, dist, electron-output, shared-lib\dist, webui\build, and companion\dist. -You may want/need to exclude these folders from backup apps too. +Windows Antimalware Executable can slow down build times by 50-100%. You can +improve performance by excluding certain folders: After cloning the companion +repo and running `yarn install` the first time (see +[Developing Core Companion](development-flow.md)) go to Windows Security > Virus +and Threat Protection > Exclusions and add node_modules from your companion +root. For completeness and a slight additional boost add: cache, dist, +electron-output, shared-lib\dist, webui\build, and companion\dist. You may +want/need to exclude these folders from backup apps too. ::: :::danger[Raspberry Pi] -It is not recommended to run Companion on a Raspberry Pi with the desktop environment installed. +It is not recommended to run Companion on a Raspberry Pi with the desktop +environment installed. ::: - diff --git a/for-developers/core-development/development-flow.md b/for-developers/core-development/development-flow.md index 0b7d6e1..1e723ca 100644 --- a/for-developers/core-development/development-flow.md +++ b/for-developers/core-development/development-flow.md @@ -5,7 +5,11 @@ sidebar_position: 10 description: The basic workflows for developing core companion code. --- -Once you've [configured your development environment](../setting-up-developer-environment.md), the following steps will get you started. The first section is for seasoned experts. For the rest of us, read on, and most importantly remember that help is only a Slack message away... +Once you've +[configured your development environment](../setting-up-developer-environment.md), +the following steps will get you started. The first section is for seasoned +experts. For the rest of us, read on, and most importantly remember that help is +only a Slack message away... ## TL;DR @@ -16,7 +20,8 @@ yarn dev Connect to it at http://localhost:8000/ -Optionally, to run the front end in dev mode with auto-refresh, open another terminal: +Optionally, to run the front end in dev mode with auto-refresh, open another +terminal: ```bash yarn dev:webui @@ -32,17 +37,22 @@ See topics below for running the launcher and docs in development mode. :::warning[Windows Note] -Be sure to [setup git line-endings behavior](../setting-up-developer-environment.md#3-install-and-setup-git) **before** cloning! +Be sure to +[setup git line-endings behavior](../setting-up-developer-environment.md#3-install-and-setup-git) +**before** cloning! ::: -Using your git client, you can clone Companion. To do it from a command line interface, change to the directory you want to contain the repo (the repo will be added as a subdirectoy) then: +Using your git client, you can clone Companion. To do it from a command line +interface, change to the directory you want to contain the repo (the repo will +be added as a subdirectoy) then: ```bash git clone https://github.com/bitfocus/companion.git ``` -This command will create a new folder called companion, containing a clone of the Bitfocus repo. Make sure to cd into this folder before continuing!!! +This command will create a new folder called companion, containing a clone of +the Bitfocus repo. Make sure to cd into this folder before continuing!!! ```bash cd companion @@ -50,15 +60,20 @@ cd companion ### Every time: Install the dependencies -When you first install and each time you update your local repository you must run the following in a terminal to install or update the dependencies. (The terminal window inside vscode is perfect for this): +When you first install and each time you update your local repository you must +run the following in a terminal to install or update the dependencies. (The +terminal window inside vscode is perfect for this): ```bash yarn install ``` -If this fails immediately after the clone, you probably did not enable corepack. Check our instructions on [Setting up your Developer Environment](../setting-up-developer-environment.md). +If this fails immediately after the clone, you probably did not enable corepack. +Check our instructions on +[Setting up your Developer Environment](../setting-up-developer-environment.md). -Note that you may have to manually rebuild the webui front-end after each update: +Note that you may have to manually rebuild the webui front-end after each +update: ```bash yarn dist:webui @@ -66,43 +81,63 @@ yarn dist:webui :::tip[Windows Tip] -Windows Antimalware Executable can slow down install and build times by 50-100%. You can improve performance by excluding certain folders: After cloning the companion repo and running `yarn install` the first time (see above) go to Windows Security > Virus and Threat Protection > Exclusions and add node_modules from your companion root. For completeness and a slight additional boost add: cache, dist, electron-output, shared-lib\dist, webui\build, and companion\dist. +Windows Antimalware Executable can slow down install and build times by 50-100%. +You can improve performance by excluding certain folders: After cloning the +companion repo and running `yarn install` the first time (see above) go to +Windows Security > Virus and Threat Protection > Exclusions and add node_modules +from your companion root. For completeness and a slight additional boost add: +cache, dist, electron-output, shared-lib\dist, webui\build, and companion\dist. You may want/need to exclude these folders from backup apps too. ::: ### Updating: Fetch or Pull -Keep the up-to-date by fetching (`git fetch`) or pulling (`git pull`). See our pages [Git Crash Course](../git-workflows/git-crashcourse.md) and [GitHub Workflow](../git-workflows/github-workflow.md) if you need an introduction or refresher on these topics. +Keep the up-to-date by fetching (`git fetch`) or pulling (`git pull`). See our +pages [Git Crash Course](../git-workflows/git-crashcourse.md) and +[GitHub Workflow](../git-workflows/github-workflow.md) if you need an +introduction or refresher on these topics. :::tip -Consider using a graphical front-end such as SmartGit, or even the GitGUI program included with git, to visualize and simplify the process. +Consider using a graphical front-end such as SmartGit, or even the GitGUI +program included with git, to visualize and simplify the process. ::: ## Working with the back-end code -After updating the code and possibly making your own additions, you can run and test the code by typing +After updating the code and possibly making your own additions, you can run and +test the code by typing ```bash yarn dev ``` -in a shell window such as powershell, bash. If you are using Visual Studio Code (VS Code), you can open a Terminal window right in the IDE. +in a shell window such as powershell, bash. If you are using Visual Studio Code +(VS Code), you can open a Terminal window right in the IDE. -Any changes you make to the code while running `yarn dev` will automatically recompile and restart Companion. +Any changes you make to the code while running `yarn dev` will automatically +recompile and restart Companion. To debug the back-end code you can: -1. Add `console.log()` or `this.logger...` (or `this.#logger...`) calls to the code. This method is particularly useful when timing is critical. -2. Use an interactive debugger. This has the advantage of allowing you to explore the current state more thoroughly, and to avoid adding "throw-away" code just for debugging. +1. Add `console.log()` or `this.logger...` (or `this.#logger...`) calls to the + code. This method is particularly useful when timing is critical. +2. Use an interactive debugger. This has the advantage of allowing you to + explore the current state more thoroughly, and to avoid adding "throw-away" + code just for debugging. - In VS Code, the simplest way to debug is to open a _Javascript Debug Terminal_ from the _Add Terminal_ pulldown menu (the '+' menu) and run either `yarn dev` (normal logging) or `yarn dev:debug` (voluminous reporting, debug-level: 'silly'). It is also possible to start these options from a menu using "_Debug: Debug npm script_" + In VS Code, the simplest way to debug is to open a _Javascript Debug + Terminal_ from the _Add Terminal_ pulldown menu (the '+' menu) and run either + `yarn dev` (normal logging) or `yarn dev:debug` (voluminous reporting, + debug-level: 'silly'). It is also possible to start these options from a menu + using "_Debug: Debug npm script_" :::tip -To include dev modules when running `yarn dev`, put the following in a file named `.env` in your top-level companion folder: +To include dev modules when running `yarn dev`, put the following in a file +named `.env` in your top-level companion folder: ``` COMPANION_DEV_MODULES= @@ -110,45 +145,61 @@ COMPANION_DEV_MODULES= (Replace "\" with the actual path.) -See [Setting a Dev Folder](../module-development/local-modules.md) for further details and options. +See [Setting a Dev Folder](../module-development/local-modules.md) for further +details and options. ::: ## Working with the (front-end) UI code -Running `yarn dev` from the base folder, will serve the prebuilt version of the webui, which will not update as you make changes to webui code. You can recompile the webui using `yarn dist:webui`, but if you wish to run the webui itself in development mode open a a second terminal window/tab and run +Running `yarn dev` from the base folder, will serve the prebuilt version of the +webui, which will not update as you make changes to webui code. You can +recompile the webui using `yarn dist:webui`, but if you wish to run the webui +itself in development mode open a a second terminal window/tab and run ```bash yarn dev:webui ``` -This will launch the development version of the webui on a different port, typically [http://localhost:5173](http://localhost:5173) +This will launch the development version of the webui on a different port, +typically [http://localhost:5173](http://localhost:5173) :::info[Important] -1. You still need to have `yarn dev` (in the base folder) running separately for this to work -2. `console.log()` code will display in the browser's console, not the command-line nor the Companion logs. +1. You still need to have `yarn dev` (in the base folder) running separately for + this to work +2. `console.log()` code will display in the browser's console, not the + command-line nor the Companion logs. ::: :::tip -You can open more than one terminal inside VS Code using the '+' menu, so in the first terminal run `yarn dev` and in the second one you can run `yarn dev:webui` +You can open more than one terminal inside VS Code using the '+' menu, so in the +first terminal run `yarn dev` and in the second one you can run `yarn dev:webui` ::: :::note -`yarn dev:webui` is equivalent to running `yarn dev` from the webui folder, i.e. `cd webui; yarn dev` +`yarn dev:webui` is equivalent to running `yarn dev` from the webui folder, i.e. +`cd webui; yarn dev` ::: #### Debugging the webui in Visual Studio Code: -The webui is written in a combination of CSS/Sass (_.scss) and [React](https://react.dev/learn) (_.tsx) code. You can debug CSS by using the Inspect feature in your web browser. To debug the React code in VS Code, follow [Microsoft's instructions to set up a _launch.json_ file](https://code.visualstudio.com/docs/nodejs/reactjs-tutorial#_debugging-react) with the following adjustments: - -- If using Chrome as your browser, select "Launch Chrome" from the menu or make sure the file shows: `"type": "chrome"` instead of `"type": "msedge",` and adjust `"name:"` as well -- Set the port number: `"url": "http://localhost:5173/"` (you can add a specific page to the URL, if desired, for fast access to that page). +The webui is written in a combination of CSS/Sass (_.scss) and +[React](https://react.dev/learn) (_.tsx) code. You can debug CSS by using the +Inspect feature in your web browser. To debug the React code in VS Code, follow +[Microsoft's instructions to set up a _launch.json_ file](https://code.visualstudio.com/docs/nodejs/reactjs-tutorial#_debugging-react) +with the following adjustments: + +- If using Chrome as your browser, select "Launch Chrome" from the menu or make + sure the file shows: `"type": "chrome"` instead of `"type": "msedge",` and + adjust `"name:"` as well +- Set the port number: `"url": "http://localhost:5173/"` (you can add a specific + page to the URL, if desired, for fast access to that page). - Add the subfolder: `"webRoot": "${workspaceFolder}/webui/src"` - The entry should in _launch.json_ should be similar to this (if using Chrome) @@ -167,31 +218,45 @@ The webui is written in a combination of CSS/Sass (_.scss) and [React](https://r } ``` -- After starting `yarn dev:webui` (and `yarn dev`, as above), press **F5** to launch a web browser and start debugging. You can set breakpoints, explore the stack and current state, etc., in the usual way. +- After starting `yarn dev:webui` (and `yarn dev`, as above), press **F5** to + launch a web browser and start debugging. You can set breakpoints, explore the + stack and current state, etc., in the usual way. -- Note that breakpoints will generally cause timeouts in the webui. If you need to debug timing-critical features, you may have to insert logging entries into the code instead. +- Note that breakpoints will generally cause timeouts in the webui. If you need + to debug timing-critical features, you may have to insert logging entries into + the code instead. ## Working with the Launcher code -The instructions above will run the 'headless' version of Companion, without the red launcher window. If you want to run or develop the launcher window, _cd_ into the `launcher` folder and run `yarn dev` +The instructions above will run the 'headless' version of Companion, without the +red launcher window. If you want to run or develop the launcher window, _cd_ +into the `launcher` folder and run `yarn dev` ```bash cd launcher yarn dev ``` -To access the Advanced Settings window: in a separate terminal _cd_ into `launcher-ui`, and run `yarn dev` from there. As with the front-end development, you need to run both of these commands to get the Advanced Settings window working. +To access the Advanced Settings window: in a separate terminal _cd_ into +`launcher-ui`, and run `yarn dev` from there. As with the front-end development, +you need to run both of these commands to get the Advanced Settings window +working. ```bash cd launcher-ui yarn dev ``` -Launcher uses a combination of Electron (for the red window) and React (for the Advanced Settings window). +Launcher uses a combination of Electron (for the red window) and React (for the +Advanced Settings window). ## Working with the Documentation -The **User Guide** and **What's New** pages, stored in the 'docs' folder of the Companion repo, are written in Markdown with [Docusaurus enhancements](https://docusaurus.io/docs/markdown-features). The help pages are built using Docusaurus. For development run the following to open a browser window that will dynamically update as you save changes. +The **User Guide** and **What's New** pages, stored in the 'docs' folder of the +Companion repo, are written in Markdown with +[Docusaurus enhancements](https://docusaurus.io/docs/markdown-features). The +help pages are built using Docusaurus. For development run the following to open +a browser window that will dynamically update as you save changes. ```bash yarn dev:docs @@ -204,11 +269,16 @@ cd docs yarn start ``` -**Developer documentation** (what you're reading now!) is maintained separately in the [Bitfocus website repo](https://github.com/bitfocus/website) under the folder _for-developers_. To contribute to the developer documentation, clone that repository, then use `yarn start` to get dynamic updates, as above. +**Developer documentation** (what you're reading now!) is maintained separately +in the [Bitfocus website repo](https://github.com/bitfocus/website) under the +folder _for-developers_. To contribute to the developer documentation, clone +that repository, then use `yarn start` to get dynamic updates, as above. :::danger[warning] -Do not edit the _user-guide_, _versioned\*_ and _whats-new_ folders in the _**website**_ repo! They are automatically updated from the main companion repo. Edit the source for those folders in the _**companion**_ repo, as described above. +Do not edit the _user-guide_, _versioned\*_ and _whats-new_ folders in the +_**website**_ repo! They are automatically updated from the main companion repo. +Edit the source for those folders in the _**companion**_ repo, as described +above. ::: - diff --git a/for-developers/core-development/intro-to-core.md b/for-developers/core-development/intro-to-core.md index 1e8342e..ff79b8b 100644 --- a/for-developers/core-development/intro-to-core.md +++ b/for-developers/core-development/intro-to-core.md @@ -5,8 +5,13 @@ sidebar_position: 1 description: Setting up a Developer Environment --- -Before you start developing you must [install the necessary tools](../setting-up-developer-environment.md) and familiarize yourself with [contributing to Companion with Git](../git-workflows/github-workflow.md). +Before you start developing you must +[install the necessary tools](../setting-up-developer-environment.md) and +familiarize yourself with +[contributing to Companion with Git](../git-workflows/github-workflow.md). -Once you have mastered these basics, continue on to the next page: [Developing Core Companion](./development-flow.md). +Once you have mastered these basics, continue on to the next page: +[Developing Core Companion](./development-flow.md). -If you need to create your own local release of Companion, check out the instructions on the [Build page](./build-companion.md). +If you need to create your own local release of Companion, check out the +instructions on the [Build page](./build-companion.md). diff --git a/for-developers/git-workflows/git-crashcourse.md b/for-developers/git-workflows/git-crashcourse.md index 2396a84..5684674 100644 --- a/for-developers/git-workflows/git-crashcourse.md +++ b/for-developers/git-workflows/git-crashcourse.md @@ -7,15 +7,30 @@ description: Introduction to git and github workflow for beginners # Git Crash Course for Companion Contributors -For first-time Git and GitHub users, contributing to open source can feel overwhelming. This guide walks you through the workflow for contributing to Companion, explaining the concepts rather than providing commands to copy and paste. The next page, [The GitHub Workflow](github-workflow.md), illustrates the process and provides specific git commands. - -Companion is open source—anyone can view and modify the code. While you're free to customize it for your own use, maintaining software quality requires coordination. Git and GitHub are the tools we use to make this possible: GitHub hosts the source code and metadata, while Git manages version control and transfers code between repositories. +For first-time Git and GitHub users, contributing to open source can feel +overwhelming. This guide walks you through the workflow for contributing to +Companion, explaining the concepts rather than providing commands to copy and +paste. The next page, [The GitHub Workflow](github-workflow.md), illustrates the +process and provides specific git commands. + +Companion is open source—anyone can view and modify the code. While you're free +to customize it for your own use, maintaining software quality requires +coordination. Git and GitHub are the tools we use to make this possible: GitHub +hosts the source code and metadata, while Git manages version control and +transfers code between repositories. :::tip -1. A GUI front-end such as SmartGit, GitGUI, can greatly simplify the overall process. See the tip under [Installing Git](installing-git#install-git) for our recommendations. +1. A GUI front-end such as SmartGit, GitGUI, can greatly simplify the overall + process. See the tip under [Installing Git](installing-git#install-git) for + our recommendations. -2. The instructions on this page describe how to contribute to repositories for which you don't have write permission, which is typically the case when you're contributing to an existing repository. Eventually you may get write-access, for example if you become the maintainer of a Companion module, in which case the flow can be simplified...but it's still good practice to develop new features on a new branch. +2. The instructions on this page describe how to contribute to repositories for + which you don't have write permission, which is typically the case when + you're contributing to an existing repository. Eventually you may get + write-access, for example if you become the maintainer of a Companion module, + in which case the flow can be simplified...but it's still good practice to + develop new features on a new branch. ::: @@ -23,50 +38,99 @@ Companion is open source—anyone can view and modify the code. While you're fre ### Why You Can't Edit Directly -As a new contributor, you don't have permission to modify code directly in the Bitfocus/companion repository. Instead, you'll propose changes from your own copy of the code. +As a new contributor, you don't have permission to modify code directly in the +Bitfocus/companion repository. Instead, you'll propose changes from your own +copy of the code. -**Forking:** Your first step is to fork the repository. This creates a copy of the repository in your GitHub account while preserving a link to the original repository. +**Forking:** Your first step is to fork the repository. This creates a copy of +the repository in your GitHub account while preserving a link to the original +repository. -**Cloning:** GitHub's online editor is limited, so you'll want to download the code to your computer. This process, called cloning, gives you the complete source code plus all version history and metadata. +**Cloning:** GitHub's online editor is limited, so you'll want to download the +code to your computer. This process, called cloning, gives you the complete +source code plus all version history and metadata. ## Making and Tracking Changes ### Understanding Commits -Git is a version control system that lets you track who changed what, when, and why. Rather than recording every keystroke, Git captures meaningful snapshots of your work called commits. - -**Branching:** Before you commit anything (see below) create and check out a new branch in your local repo. All changes added (committed) to this branch will be "bundled" for the subsequent pull request described in the next section. The branch allows you to organize your changes into several commits and will provide the mechanism for updating your code in response to reviewer's comments on your proposed code changes. - -**Staging:** Before creating a commit, you select which changes to include by "staging" files to what git calls the "index". You don't need to commit everything at once—only the changes that logically belong together. If you edit a staged file again before committing, the file must be re-staged to include those edits in the commit. You can take advantage of this behavior by staging working versions that you can rollback to while testing further code changes. - -**Committing:** The commit command creates a snapshot of your staged files. You'll write a commit message describing what the snapshot contains. Git then stores this in its database, allowing you or others to restore that exact state later. +Git is a version control system that lets you track who changed what, when, and +why. Rather than recording every keystroke, Git captures meaningful snapshots of +your work called commits. + +**Branching:** Before you commit anything (see below) create and check out a new +branch in your local repo. All changes added (committed) to this branch will be +"bundled" for the subsequent pull request described in the next section. The +branch allows you to organize your changes into several commits and will provide +the mechanism for updating your code in response to reviewer's comments on your +proposed code changes. + +**Staging:** Before creating a commit, you select which changes to include by +"staging" files to what git calls the "index". You don't need to commit +everything at once—only the changes that logically belong together. If you edit +a staged file again before committing, the file must be re-staged to include +those edits in the commit. You can take advantage of this behavior by staging +working versions that you can rollback to while testing further code changes. + +**Committing:** The commit command creates a snapshot of your staged files. +You'll write a commit message describing what the snapshot contains. Git then +stores this in its database, allowing you or others to restore that exact state +later. ## Sharing Your Changes ### Pushing to Your Fork -Commits initially exist only on your computer. To transfer them to GitHub, you'll "push" them to your remote repository (see the illustration on [The GitHub Workflow](github-workflow.md) page). When you cloned your fork, Git automatically added it as a remote location named "origin." (Note: on the next page we suggest renaming it "personal" -- either way, you push to your fork not to the original bitfocus repo.) Pushing to your fork uploads all commits made since your last push. +Commits initially exist only on your computer. To transfer them to GitHub, +you'll "push" them to your remote repository (see the illustration on +[The GitHub Workflow](github-workflow.md) page). When you cloned your fork, Git +automatically added it as a remote location named "origin." (Note: on the next +page we suggest renaming it "personal" -- either way, you push to your fork not +to the original bitfocus repo.) Pushing to your fork uploads all commits made +since your last push. ### Creating a Pull Request (PR) -Once your changes are in your GitHub fork, you'll create a pull request to propose including them in the original Bitfocus/companion repository. The GitHub website automatically detects your pushed branch and guides you through the process of creating a pull request. +Once your changes are in your GitHub fork, you'll create a pull request to +propose including them in the original Bitfocus/companion repository. The GitHub +website automatically detects your pushed branch and guides you through the +process of creating a pull request. ## Avoiding Merge Conflicts ### The Challenge of Concurrent Changes -GitHub indicates whether your pull request can merge automatically. If you're the only person who modified those files, merging is straightforward. However, if someone else changed the same files while you were working, Git faces competing versions and can't automatically decide how to combine them. +GitHub indicates whether your pull request can merge automatically. If you're +the only person who modified those files, merging is straightforward. However, +if someone else changed the same files while you were working, Git faces +competing versions and can't automatically decide how to combine them. -In such cases, you or a core developer must manually review both versions and choose which lines to keep. This can break functionality, especially if you've made substantial changes that were tested against the older codebase. +In such cases, you or a core developer must manually review both versions and +choose which lines to keep. This can break functionality, especially if you've +made substantial changes that were tested against the older codebase. ### Pull Before Push -To avoid this situation, adopt the habit of "pulling before pushing"—check for others' changes before uploading yours. This matters even for files you didn't modify, since those changes might affect your code's behavior. +To avoid this situation, adopt the habit of "pulling before pushing"—check for +others' changes before uploading yours. This matters even for files you didn't +modify, since those changes might affect your code's behavior. -**The Upstream Remote:** Your local repository starts with just one remote: depending on what you cloned, "origin" points either to your fork or the bitfocus repo on GitHub. If you follow the instructions on [The GitHub Workflow](github-workflow.md) page, origin points to the bitfocus repo, so just pull from origin. Some people prefer to clone their fork and call _it_ "origin", in which case the convention is to add the Bitfocus repo as a second remote and call it "upstream." Either way, it is simplest to pull directly from the Bitfocus repo to make sure you're up-to-date. +**The Upstream Remote:** Your local repository starts with just one remote: +depending on what you cloned, "origin" points either to your fork or the +bitfocus repo on GitHub. If you follow the instructions on +[The GitHub Workflow](github-workflow.md) page, origin points to the bitfocus +repo, so just pull from origin. Some people prefer to clone their fork and call +_it_ "origin", in which case the convention is to add the Bitfocus repo as a +second remote and call it "upstream." Either way, it is simplest to pull +directly from the Bitfocus repo to make sure you're up-to-date. -**PR Workflow:** Pull from upstream to get the latest changes, resolve any conflicts yourself, test thoroughly, then push to your GitHub fork. A good practice is to rebase your branch onto the latest commit (aka HEAD) in the main branch before pushing. +**PR Workflow:** Pull from upstream to get the latest changes, resolve any +conflicts yourself, test thoroughly, then push to your GitHub fork. A good +practice is to rebase your branch onto the latest commit (aka HEAD) in the main +branch before pushing. ## Growing as a Contributor -If you become a regular contributor, the core developers may grant you write access to the repository, allowing you to push changes directly rather than going through pull requests. +If you become a regular contributor, the core developers may grant you write +access to the repository, allowing you to push changes directly rather than +going through pull requests. diff --git a/for-developers/git-workflows/github-workflow.md b/for-developers/git-workflows/github-workflow.md index eff2897..defe12c 100644 --- a/for-developers/git-workflows/github-workflow.md +++ b/for-developers/git-workflows/github-workflow.md @@ -7,20 +7,37 @@ description: Introduction to git and github workflow for beginners ![image](images/github-contribution-workflow.png) -The following is the basic workflow for contributing to Companion (and many other open-source repositories) on GitHub. The order of operations is a key to keeping everything straight... This page assumes basic knowledge of Git and GitHub. To learn Git, check out our [Git Crashcourse](git-crashcourse), or [Git's documentation](https://git-scm.com/learn) or the many online resources. +The following is the basic workflow for contributing to Companion (and many +other open-source repositories) on GitHub. The order of operations is a key to +keeping everything straight... This page assumes basic knowledge of Git and +GitHub. To learn Git, check out our [Git Crashcourse](git-crashcourse), or +[Git's documentation](https://git-scm.com/learn) or the many online resources. -The examples below use the core Companion repo, bitfocus/companion, for specificity. If you are contributing to a module, substitute the module's repository name for bitfocus/companion. (For example, bitfocus/companion-module-generic-http.) +The examples below use the core Companion repo, bitfocus/companion, for +specificity. If you are contributing to a module, substitute the module's +repository name for bitfocus/companion. (For example, +bitfocus/companion-module-generic-http.) :::tip -1. A GUI front-end such as SmartGit, GitGUI, can greatly simplify the overall process. See the tip under [Installing Git](installing-git#install-git) for our recommendations. +1. A GUI front-end such as SmartGit, GitGUI, can greatly simplify the overall + process. See the tip under [Installing Git](installing-git#install-git) for + our recommendations. -2. The instructions on this page describe how to contribute to repositories for which you don't have write permission, which is typically the case when you're contributing to an existing repository. Eventually you may get write-access, for example if you become the maintainer of a Companion module, in which case the flow can be simplified...but it's still good practice to develop new features on a new branch. - ::: +2. The instructions on this page describe how to contribute to repositories for + which you don't have write permission, which is typically the case when + you're contributing to an existing repository. Eventually you may get + write-access, for example if you become the maintainer of a Companion module, + in which case the flow can be simplified...but it's still good practice to + develop new features on a new branch. ::: :::note[Expert Note] -The following outline names the bitfocus remote "origin" and your remote fork "personal". This seems much clearer than the convention of naming the bitfocus repo "upstream" and your remote fork "origin" (which it is not!). The convention recommended here eliminates a step and also ensures that your pulls come from the Bitfocus repo. Many thanks to Brian Teeman for this and other suggestions. +The following outline names the bitfocus remote "origin" and your remote fork +"personal". This seems much clearer than the convention of naming the bitfocus +repo "upstream" and your remote fork "origin" (which it is not!). The convention +recommended here eliminates a step and also ensures that your pulls come from +the Bitfocus repo. Many thanks to Brian Teeman for this and other suggestions. ::: @@ -28,7 +45,9 @@ The following outline names the bitfocus remote "origin" and your remote fork "p :::warning[Windows Users!] -If you are cloning to a Windows computer be sure to [configure git line-endings as described here](installing-git.md#configure-git) _**before**_ cloning Companion. +If you are cloning to a Windows computer be sure to +[configure git line-endings as described here](installing-git.md#configure-git) +_**before**_ cloning Companion. ::: @@ -40,33 +59,51 @@ git clone https://github.com/bitfocus/companion.git :::note -The Bitfocus repository is read-only for most users. In the next step we will create a writeable "fork" of the Bitfocus repo that will be used for sending in proposed code changes (PRs) +The Bitfocus repository is read-only for most users. In the next step we will +create a writeable "fork" of the Bitfocus repo that will be used for sending in +proposed code changes (PRs) ::: -**updating**: Once your local repository has been established, use `git fetch` or `git pull` to keep it up-to-date. (Some GUI frontends can automate this part.) +**updating**: Once your local repository has been established, use `git fetch` +or `git pull` to keep it up-to-date. (Some GUI frontends can automate this +part.) ## 1b. Fork Companion to your GitHub account -Back on the [Companion GitHub page](https://github.com/bitfocus/companion) or the module's GitHub page, click on the `Fork` button in the Code tab. This will create a repository under your GitHub account that you can write to. +Back on the [Companion GitHub page](https://github.com/bitfocus/companion) or +the module's GitHub page, click on the `Fork` button in the Code tab. This will +create a repository under your GitHub account that you can write to. -**updating**: Once the fork has been created, use the "Sync Fork" button in GitHub to keep it up-to-date. +**updating**: Once the fork has been created, use the "Sync Fork" button in +GitHub to keep it up-to-date. ### Add the fork as a remote to your local repository -Your local repository will need two "know" two remote (GitHub) repos -- one for keeping in sync with Bitfocus and the other for writing your code changes. We suggest naming this second one "personal" for clarity -- it is your personal fork of companion _on GitHub_: +Your local repository will need two "know" two remote (GitHub) repos -- one for +keeping in sync with Bitfocus and the other for writing your code changes. We +suggest naming this second one "personal" for clarity -- it is your personal +fork of companion _on GitHub_: -On the GitHub page for your new fork, copy the HTTPS link to your fork using the green **<> Code ▼** button. Then paste it on a line starting with `it remote add personal`. It should look like this (for core Companion): +On the GitHub page for your new fork, copy the HTTPS link to your fork using the +green +**<> Code ▼** button. Then paste it on a line starting with +`it remote add personal`. It should look like this (for core Companion): ```bash git remote add personal https://github.com//companion.git ``` -(In a GUI frontend you would select "Add Remote..." from a menu. SmartGit, for example, will automatically pick up the URL from your clipboard when you do this.) +(In a GUI frontend you would select "Add Remote..." from a menu. SmartGit, for +example, will automatically pick up the URL from your clipboard when you do +this.) :::note -By default, the Bitfocus remote that you cloned above, was named "origin". So "origin" refers to Bitfocus (the "origin" of your clone) and "personal" refers to your fork on GitHub. +By default, the Bitfocus remote that you cloned above, was named "origin". So +"origin" refers to Bitfocus (the "origin" of your clone) and "personal" refers +to your fork on GitHub. ::: @@ -76,17 +113,21 @@ By default, the Bitfocus remote that you cloned above, was named "origin". So "o git switch -c ``` -(In a GUI frontend you would select "Add Branch..." from a menu.) This creates and checks out the new branch. +(In a GUI frontend you would select "Add Branch..." from a menu.) This creates +and checks out the new branch. -Next, modify/add code for your feature of bug-fix using your favorite coding tools. +Next, modify/add code for your feature of bug-fix using your favorite coding +tools. -When you are satisfied with some or all of your changes, commit them to the new branch +When you are satisfied with some or all of your changes, commit them to the new +branch ```bash git commit -m 'message' ``` -This is where you really want to be using a GUI front-end to git to keep track of everything! +This is where you really want to be using a GUI front-end to git to keep track +of everything! ## 3. Push the branch to your GitHub fork @@ -94,12 +135,18 @@ This is where you really want to be using a GUI front-end to git to keep track o git push -u personal ``` -(In a GUI frontend you would select "Push to..." from a menu and select "personal".) After the first push, you can push further commits on that branch using just `git push` +(In a GUI frontend you would select "Push to..." from a menu and select +"personal".) After the first push, you can push further commits on that branch +using just `git push` ## 4. Submit a Pull Request (PR) to Bitfocus -Once you are satisfied with your code, submit a PR from the GitHub page for your fork. GitHub will guide you through the process. +Once you are satisfied with your code, submit a PR from the GitHub page for your +fork. GitHub will guide you through the process. -Subsequent commits that you push to this branch will automatically be included in the PR. +Subsequent commits that you push to this branch will automatically be included +in the PR. -Occasionally, you will make changes to the PR directly on GitHub. In these cases you will need to fetch or pull the changes from your GitHub fork back into your local repo to keep things synchronized. +Occasionally, you will make changes to the PR directly on GitHub. In these cases +you will need to fetch or pull the changes from your GitHub fork back into your +local repo to keep things synchronized. diff --git a/for-developers/git-workflows/installing-git.md b/for-developers/git-workflows/installing-git.md index eaabbde..738414b 100644 --- a/for-developers/git-workflows/installing-git.md +++ b/for-developers/git-workflows/installing-git.md @@ -5,35 +5,63 @@ sidebar_position: 1 description: Instructions for installing git on your computer. --- -If you have never used git or github before, have a read of our [Git crashcourse](git-crashcourse.md). Before you get started, however you must install and configure git on your computer. +If you have never used git or github before, have a read of our +[Git crashcourse](git-crashcourse.md). Before you get started, however you must +install and configure git on your computer. ## Install Git -Install git following the instructions on [their website](https://git-scm.com/install/). +Install git following the instructions on +[their website](https://git-scm.com/install/). -Consider installing a graphical front-end to git: it can greatly simplify your git workflow. The following three popular options run on Windows, Mac and Linux. Many other GUI options are listed on [the git website](https://git-scm.com/tools/guis). +Consider installing a graphical front-end to git: it can greatly simplify your +git workflow. The following three popular options run on Windows, Mac and Linux. +Many other GUI options are listed on +[the git website](https://git-scm.com/tools/guis). :::note -You do not have to limit yourself to a single tool: because of the way Git works on your computer, you can use any or all of these simultaneously. Each tool has it's benefits, so you may find yourself quite naturally using each one to its strength. +You do not have to limit yourself to a single tool: because of the way Git works +on your computer, you can use any or all of these simultaneously. Each tool has +it's benefits, so you may find yourself quite naturally using each one to its +strength. ::: -- The standard Git install, linked above, installs **Git GUI**, which though minimal is good at what it does, especially if you use the "_Visualize All Branch History_" viewer launched from the _Repository_ menu. On Windows the option to "Open Git Gui here" is added to the right-click menu for folders in the File Explorer. - -- [**SmartGit**](https://www.smartgit.dev/) adds a fair bit of functionality and ease-of-use especially for keeping up with changes in the main repository and organizing multiple repositories. It is free for use with public (open-source) repositories. - -- [**Visual Studio Code**](https://code.visualstudio.com/) (VS Code), the IDE we recommend, also provides some [integrated git management](https://code.visualstudio.com/docs/sourcecontrol/overview), which can be enhanced with various plugins such as [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens), [Git History](https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory), and [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph). - -- [**GitHub Desktop**](https://github.com/apps/desktop) works well in simple cases and integrates well with GitHub. +- The standard Git install, linked above, installs **Git GUI**, which though + minimal is good at what it does, especially if you use the "_Visualize All + Branch History_" viewer launched from the _Repository_ menu. On Windows the + option to "Open Git Gui here" is added to the right-click menu for folders in + the File Explorer. + +- [**SmartGit**](https://www.smartgit.dev/) adds a fair bit of functionality and + ease-of-use especially for keeping up with changes in the main repository and + organizing multiple repositories. It is free for use with public (open-source) + repositories. + +- [**Visual Studio Code**](https://code.visualstudio.com/) (VS Code), the IDE we + recommend, also provides some + [integrated git management](https://code.visualstudio.com/docs/sourcecontrol/overview), + which can be enhanced with various plugins such as + [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens), + [Git History](https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory), + and + [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph). + +- [**GitHub Desktop**](https://github.com/apps/desktop) works well in simple + cases and integrates well with GitHub. ## Configure Git :::warning[Windows Note] -Companion’s `prettier` config requires `eol=lf`, but the system default (in C:/Program Files/Git/etc/gitconfig) may have set autocrlf to true during installation. +Companion’s `prettier` config requires `eol=lf`, but the system default (in +C:/Program Files/Git/etc/gitconfig) may have set autocrlf to true during +installation. -In order for `git clone` to give you `lf` endings, i.e. before you have even downloaded the repository, this default needs to be overridden _**before you clone the companion repository**_. In a git bash window type: +In order for `git clone` to give you `lf` endings, i.e. before you have even +downloaded the repository, this default needs to be overridden _**before you +clone the companion repository**_. In a git bash window type: ```bash git config set --global core.autocrlf false @@ -41,4 +69,3 @@ git config set --global core.eol lf ``` ::: - diff --git a/for-developers/git-workflows/versioning.md b/for-developers/git-workflows/versioning.md index f7a946d..bb96d1d 100644 --- a/for-developers/git-workflows/versioning.md +++ b/for-developers/git-workflows/versioning.md @@ -7,16 +7,27 @@ description: How we handle versioning for Companion ## Versioning -Companion follows the [SemVer](https://semver.org/) convention for naming versions. This page describes how we handle versioning for Companion. It will provide information to users how to understand version numbers and information on developers how to generate version numbers. +Companion follows the [SemVer](https://semver.org/) convention for naming +versions. This page describes how we handle versioning for Companion. It will +provide information to users how to understand version numbers and information +on developers how to generate version numbers. -The main goal of our versioning scheme is to make sure that it is easy for the users of the different parts of Companion to estimate whether different versions are compatible to each other and which impact a different version may have. +The main goal of our versioning scheme is to make sure that it is easy for the +users of the different parts of Companion to estimate whether different versions +are compatible to each other and which impact a different version may have. -Companion is not a monolithic application and different version numbers apply to different parts of the software. Versions must not be redundant, that means for one part of Companion there has to be one place where it's version is stored. If code or functionality is changed, one change must not impact more than one version number. +Companion is not a monolithic application and different version numbers apply to +different parts of the software. Versions must not be redundant, that means for +one part of Companion there has to be one place where it's version is stored. If +code or functionality is changed, one change must not impact more than one +version number. ### General scheme - We use a scheme of three numbers separated by dots. E.g.: `1.23.45` -- The three parts are called: major.minor.patch, that means the first number denotes the major-version, the second number the minor-version and the last number the patch-version. +- The three parts are called: major.minor.patch, that means the first number + denotes the major-version, the second number the minor-version and the last + number the patch-version. - Each number can only be greater or equal than zero. - Each number can only be a whole number. - Each number can only be counted up. @@ -25,27 +36,65 @@ Companion is not a monolithic application and different version numbers apply to ### Version of Companion -We are following the standards given by semantic versioning, adopted for end-user applications. That means wherever semantic versioning relates to an API, we relate to end-user functionality. +We are following the standards given by semantic versioning, adopted for +end-user applications. That means wherever semantic versioning relates to an +API, we relate to end-user functionality. -- The major-version is counted up if there are breaking changes in the core of companion (on either a technical level, or a significant change in how users use the application). E.g.: stored database files will not be usable any more, APIs will not be usable any more - The major version is not a marketing instrument, we hope to avoid breaking changes as long as possible and so the major version should not change often. This is does not mean lack of innovation and actually less major versions are good. -- The minor-version is counted up if functionality is added or changed in the core of companion. Added or changed functionality means that there is an intention to add or change functionality which the user can recognize. Typical examples are: a new item, better naming of an item, changed/better color of an item, changed/improved placement, changed behaviour like search giving grouped results instead ungrouped or results with scrollbars instead of no scrollbars. -- The patch-version is counted up if there are changes which do not add or change functionality for the user or the change is that a broken functionality will be fixed. Typical examples are: refactoring code, bundling different versions of libraries or frameworks, fixing a bug without adding new functionality or changing the way it should have been working from the start. -- additionally to the major.minor.patch scheme we are using tags for beta and experimental builds in the form of: major.minor.patch+build-channel-commit - - build is the integer build number which counts up with every build generated by the Companion build system - - channel is the release-channel like beta or experimental, it corresponds to the development branch, the stable-channel is not added to the version +- The major-version is counted up if there are breaking changes in the core of + companion (on either a technical level, or a significant change in how users + use the application). E.g.: stored database files will not be usable any more, + APIs will not be usable any more The major version is not a marketing + instrument, we hope to avoid breaking changes as long as possible and so the + major version should not change often. This is does not mean lack of + innovation and actually less major versions are good. +- The minor-version is counted up if functionality is added or changed in the + core of companion. Added or changed functionality means that there is an + intention to add or change functionality which the user can recognize. Typical + examples are: a new item, better naming of an item, changed/better color of an + item, changed/improved placement, changed behaviour like search giving grouped + results instead ungrouped or results with scrollbars instead of no scrollbars. +- The patch-version is counted up if there are changes which do not add or + change functionality for the user or the change is that a broken functionality + will be fixed. Typical examples are: refactoring code, bundling different + versions of libraries or frameworks, fixing a bug without adding new + functionality or changing the way it should have been working from the start. +- additionally to the major.minor.patch scheme we are using tags for beta and + experimental builds in the form of: major.minor.patch+build-channel-commit + - build is the integer build number which counts up with every build generated + by the Companion build system + - channel is the release-channel like beta or experimental, it corresponds to + the development branch, the stable-channel is not added to the version - commit is the hash of the commit head was at when building this version ### Version of Companion's APIs -Other applications or modules communicate with Companion by the use of application programming interfaces (APIs). It is the ultimate goal of API versioning to ensure compatibility. -We are strictly following semantic versioning for our APIs. +Other applications or modules communicate with Companion by the use of +application programming interfaces (APIs). It is the ultimate goal of API +versioning to ensure compatibility. We are strictly following semantic +versioning for our APIs. ### Version of Modules -We are following the standards given by semantic versioning, adopted for end-user applications. That means wherever semantic versioning relates to an API, we relate to end-user functionality. +We are following the standards given by semantic versioning, adopted for +end-user applications. That means wherever semantic versioning relates to an +API, we relate to end-user functionality. -- The major-version is counted up if there are breaking changes in the module. E.g.: the module is not compatible to the API used before (common for modules upgraded for Companion v3), the module drops support for a device or a variant of a device, the module changes in a way that stored user data can't be used any more (no upgrade script provided) -- The minor-version is counted up if functionality is added or changed in the module. Added or changed functionality means that there is an intention to add or change functionality which the user can recognize. Typical examples are: a new variable, better naming of an option, changed behaviour like offering variables parsing for textinputs, changed/better sorting of items. -- The patch-version is counted up if there are changes which do not add or change functionality for the user or the change is that a broken functionality will be fixed. Typical examples are: refactoring code, bundling different versions of libraries or frameworks, fixing a bug without adding new functionality or changing the way it should have been working from the start, updating help-file. -- modules are free to add additional tags like build numbers or release channel to their version, which can limit whether the version is published as a stable or beta version in the developer portal. +- The major-version is counted up if there are breaking changes in the module. + E.g.: the module is not compatible to the API used before (common for modules + upgraded for Companion v3), the module drops support for a device or a variant + of a device, the module changes in a way that stored user data can't be used + any more (no upgrade script provided) +- The minor-version is counted up if functionality is added or changed in the + module. Added or changed functionality means that there is an intention to add + or change functionality which the user can recognize. Typical examples are: a + new variable, better naming of an option, changed behaviour like offering + variables parsing for textinputs, changed/better sorting of items. +- The patch-version is counted up if there are changes which do not add or + change functionality for the user or the change is that a broken functionality + will be fixed. Typical examples are: refactoring code, bundling different + versions of libraries or frameworks, fixing a bug without adding new + functionality or changing the way it should have been working from the start, + updating help-file. +- modules are free to add additional tags like build numbers or release channel + to their version, which can limit whether the version is published as a stable + or beta version in the developer portal. diff --git a/for-developers/index.md b/for-developers/index.md index 947033b..c78b837 100644 --- a/for-developers/index.md +++ b/for-developers/index.md @@ -5,12 +5,20 @@ sidebar_position: 0 description: Overview of the developer documentation --- -These pages provide information for people who would like to contribute to the Bitfocus Companion Open-Source Project. +These pages provide information for people who would like to contribute to the +Bitfocus Companion Open-Source Project. -All contributors should familiarize themselves with [Git and GitHub flows](./git-workflows/git-crashcourse.md), which provide the fundamental framework for contributing and for tracking changes. +All contributors should familiarize themselves with +[Git and GitHub flows](./git-workflows/git-crashcourse.md), which provide the +fundamental framework for contributing and for tracking changes. -In order to develop and test code on your own computer, you will need to [Install the Developer Tools](./setting-up-developer-environment.md). From there, you can choose your path: developing a module or contributing to core companion: +In order to develop and test code on your own computer, you will need to +[Install the Developer Tools](./setting-up-developer-environment.md). From +there, you can choose your path: developing a module or contributing to core +companion: -- Developers wanting to contribute a module or contribute to an existing module can proceed to the [Companion Modules](./module-development/home.md) pages. +- Developers wanting to contribute a module or contribute to an existing module + can proceed to the [Companion Modules](./module-development/home.md) pages. -- Developers interested in contributing to the core Companion functionality should proceed to [Core Companion](./core-development/intro-to-core.md) +- Developers interested in contributing to the core Companion functionality + should proceed to [Core Companion](./core-development/intro-to-core.md) diff --git a/for-developers/linking-to-companion.md b/for-developers/linking-to-companion.md index bcfc920..75aea6e 100644 --- a/for-developers/linking-to-companion.md +++ b/for-developers/linking-to-companion.md @@ -4,12 +4,16 @@ sidebar_label: Linking to Companion sidebar_position: 100 --- -If you make, sell or advertise a product which can be controlled with Companion you can place a badge referring to Companion along with it. Typically you'll want to place a badge on your product's website, but you can also use it in print. -You can download the Badge here: [https://companion.free/img/companion-badge.png](https://companion.free/img/companion-badge.png) +If you make, sell or advertise a product which can be controlled with Companion +you can place a badge referring to Companion along with it. Typically you'll +want to place a badge on your product's website, but you can also use it in +print. You can download the Badge here: +[https://companion.free/img/companion-badge.png](https://companion.free/img/companion-badge.png) ![Controllable by Companion](https://companion.free/img/companion-badge.png) -When integrating the badge on your website(s), you are free to host the image yourself or to link the image on our server. +When integrating the badge on your website(s), you are free to host the image +yourself or to link the image on our server. Use this html to show the badge: @@ -17,14 +21,19 @@ Use this html to show the badge: Controllable by Companion ``` -At the points where it says `"ref=bitfocus"` replace the word _bitfocus_ with a reference to you or your product (only letters and numbers are allowed). +At the points where it says `"ref=bitfocus"` replace the word _bitfocus_ with a +reference to you or your product (only letters and numbers are allowed). -You can scale the image to fit in your website, as long as it is still readable, you may not change its color, rotation, animate it or change it in any other way than scaling. +You can scale the image to fit in your website, as long as it is still readable, +you may not change its color, rotation, animate it or change it in any other way +than scaling. You are not allowed to: -- use this Badge without advertising a product which is controllable by Companion without a custom module +- use this Badge without advertising a product which is controllable by + Companion without a custom module - alter the appearance of this badge - hyperlink the badge to any other than the given site -- hyperlink the badge to bitfocus.io with redirectors or link shortening services +- hyperlink the badge to bitfocus.io with redirectors or link shortening + services - use the badge in an inappropriate way diff --git a/for-developers/maintenance-team/making-a-release-of-companion.md b/for-developers/maintenance-team/making-a-release-of-companion.md index 32725e3..18068a6 100644 --- a/for-developers/maintenance-team/making-a-release-of-companion.md +++ b/for-developers/maintenance-team/making-a-release-of-companion.md @@ -5,7 +5,8 @@ sidebar_position: 1 description: Steps to make a new release --- -This is the release procedure for Companion, not for modules. You probably don't want this file. +This is the release procedure for Companion, not for modules. You probably don't +want this file. ## Major/minor release @@ -14,31 +15,51 @@ This is the release procedure for Companion, not for modules. You probably don't - Starting on the main branch, ensure your local copy is up to date - create and push a `stable-x.x` branch, we will work from this from now on - Ensure the changelog is updated for the release -- Ensure the version in each `package.json` is correct. (unless it was already set to 0.0.0) +- Ensure the version in each `package.json` is correct. (unless it was already + set to 0.0.0) - Commit and push any changes you have made -- Ensure the docs are synced to the website, you may need to run the `Sync Docs to Website` workflow for the release branch - - Make sure the docs got the update, built and deployed https://github.com/bitfocus/website/actions +- Ensure the docs are synced to the website, you may need to run the + `Sync Docs to Website` workflow for the release branch + - Make sure the docs got the update, built and deployed + https://github.com/bitfocus/website/actions - Tag and push the new release from your `stable-x.x` branch. - Merge the result to main, ideally as a fast-forward merge - Push the updated main -- Create the new github release https://github.com/bitfocus/companion/releases using the previous one as a template, replacing the changes with the contents of the changelog +- Create the new github release https://github.com/bitfocus/companion/releases + using the previous one as a template, replacing the changes with the contents + of the changelog - Make sure the builds complete successfully, retry the runs if they fail -- Once the builds have completed, run the [CompanionPi](https://github.com/bitfocus/companion-pi/actions/workflows/companionpi.yml) workflow to produce the new image, providing the name of the git tag you just created. +- Once the builds have completed, run the + [CompanionPi](https://github.com/bitfocus/companion-pi/actions/workflows/companionpi.yml) + workflow to produce the new image, providing the name of the git tag you just + created. - Ask the moderators to make a facebook post -- Back on the `main` branch, update the version number to be for the next minor version (eg 3.1.0 should become 3.2.0) and add the new version as an entry in `shared-lib/lib/Paths.cts` -- Merge `main` into `develop`, and ensure the version number conflicts are handled correctly -- Run the release, and make sure the top bar doesnt report the build as experimental or out of date +- Back on the `main` branch, update the version number to be for the next minor + version (eg 3.1.0 should become 3.2.0) and add the new version as an entry in + `shared-lib/lib/Paths.cts` +- Merge `main` into `develop`, and ensure the version number conflicts are + handled correctly +- Run the release, and make sure the top bar doesnt report the build as + experimental or out of date ## Patch release -- Read through the commit history of the `main` branch, to see if there are any fixes that should be applied to the stable branch. +- Read through the commit history of the `main` branch, to see if there are any + fixes that should be applied to the stable branch. - If you are unsure, reach out to the author of the fix! - Ensure the changelog is updated for the release -- Ensure the version in each `package.json` is correct. (unless it was already set to 0.0.0) +- Ensure the version in each `package.json` is correct. (unless it was already + set to 0.0.0) - Commit and push any changes you have made - Tag and push the new release from your `stable-x.x` branch. -- Create the new github release https://github.com/bitfocus/companion/releases using the previous one as a template, replacing the changes with the contents of the changelog +- Create the new github release https://github.com/bitfocus/companion/releases + using the previous one as a template, replacing the changes with the contents + of the changelog - Make sure the builds complete successfully, retry the runs if they fail -- Once the builds have completed, run the [CompanionPi](https://github.com/bitfocus/companion-pi/actions/workflows/companionpi.yml) workflow to produce the new image, providing the name of the git tag you just created. +- Once the builds have completed, run the + [CompanionPi](https://github.com/bitfocus/companion-pi/actions/workflows/companionpi.yml) + workflow to produce the new image, providing the name of the git tag you just + created. - (Rare) Ask the moderators to make a facebook post -- Run the release, and make sure the top bar doesnt report the build as experimental or out of date +- Run the release, and make sure the top bar doesnt report the build as + experimental or out of date diff --git a/for-developers/module-development/api-changes/index.md b/for-developers/module-development/api-changes/index.md index fe5a74f..b6a9167 100644 --- a/for-developers/module-development/api-changes/index.md +++ b/for-developers/module-development/api-changes/index.md @@ -4,4 +4,6 @@ description: Outline of all changes auto_toc: true --- -This section describes the changes made in each new release of @companion-module/base (the module API), and which version of Companion first supports these changes. Click on the links to read more about each topic. +This section describes the changes made in each new release of +@companion-module/base (the module API), and which version of Companion first +supports these changes. Click on the links to read more about each topic. diff --git a/for-developers/module-development/api-changes/v1.10.md b/for-developers/module-development/api-changes/v1.10.md index a04598e..26b8823 100644 --- a/for-developers/module-development/api-changes/v1.10.md +++ b/for-developers/module-development/api-changes/v1.10.md @@ -5,22 +5,31 @@ sidebar_position: -110 ## Custom headlines for preset actions, feedbacks and steps {#preset-headlines} -Presets can now define a `headline` value for each action, feedback and step, to be used as the user-editable label for the action/feedback/step. +Presets can now define a `headline` value for each action, feedback and step, to +be used as the user-editable label for the action/feedback/step. ## Array support for merging multiple Bonjour queries {#bonjour-arrays} -Inside your `companion/manifest.json`, each bonjour query defined can now be an array of queries, allowing two queries to be merged and used for one config field. +Inside your `companion/manifest.json`, each bonjour query defined can now be an +array of queries, allowing two queries to be merged and used for one config +field. ## Extended format support for feedback image buffers {#image-buffers} The `imageBuffer` property from advanced feedbacks can now be in more formats. -To do this, there is a [new `imageBufferEncoding` property](https://bitfocus.github.io/companion-module-base/interfaces/CompanionImageBufferEncoding.html). This allows you to specify how the colors are packed in your buffer. +To do this, there is a +[new `imageBufferEncoding` property](https://bitfocus.github.io/companion-module-base/interfaces/CompanionImageBufferEncoding.html). +This allows you to specify how the colors are packed in your buffer. -Additionally, the `imageBufferPosition` property has gained [a new `drawScale` property](https://bitfocus.github.io/companion-module-base/interfaces/CompanionImageBufferPosition.html#drawscale). This can be used to scale how the buffer is drawn, allowing to either match the higher resolution we now draw at, or to avoid scaling a buffer yourself. +Additionally, the `imageBufferPosition` property has gained +[a new `drawScale` property](https://bitfocus.github.io/companion-module-base/interfaces/CompanionImageBufferPosition.html#drawscale). +This can be used to scale how the buffer is drawn, allowing to either match the +higher resolution we now draw at, or to avoid scaling a buffer yourself. :::tip -Make sure to not use really large buffers, as that will become a bottleneck for your module. +Make sure to not use really large buffers, as that will become a bottleneck for +your module. ::: diff --git a/for-developers/module-development/api-changes/v1.12.md b/for-developers/module-development/api-changes/v1.12.md index 56c9ffb..804b507 100644 --- a/for-developers/module-development/api-changes/v1.12.md +++ b/for-developers/module-development/api-changes/v1.12.md @@ -6,9 +6,12 @@ description: Module permissions & isVisibleExpression ## Module permissions for enhanced security {#permissions} -As of @companion-module/base v1.12, modules will be run with the nodejs permissions model enabled. This will allow us to inform users about the requirements of modules. +As of @companion-module/base v1.12, modules will be run with the nodejs +permissions model enabled. This will allow us to inform users about the +requirements of modules. -You can opt into additional permissions by defining the `permissions` object in your `manifest.json` +You can opt into additional permissions by defining the `permissions` object in +your `manifest.json` The permissions you can request are: @@ -19,30 +22,36 @@ The permissions you can request are: :::danger -If possible it is advised to not use any of these permissions, as in the future it will show your module as needing extra permissions. +If possible it is advised to not use any of these permissions, as in the future +it will show your module as needing extra permissions. ::: :::tip -In the future we expect to make the filesystem permission more granular, with users being able to specify certain paths that your module is allowed to access. +In the future we expect to make the filesystem permission more granular, with +users being able to specify certain paths that your module is allowed to access. We would recommend planning for this in your module implementation. ::: ## Expression syntax support for `isVisible` on option fields {#isvisible-expressions} -The `isVisible` functions that can be defined on option fields can now be written in the companion expression syntax through a new `isVisibleExpression` property. +The `isVisible` functions that can be defined on option fields can now be +written in the companion expression syntax through a new `isVisibleExpression` +property. :::tip -We advise all uses to be updated to the new syntax, the old syntax is now deprecated and support will be dropped in a future release. +We advise all uses to be updated to the new syntax, the old syntax is now +deprecated and support will be dropped in a future release. ::: ## Port-based filtering for Bonjour queries {#bonjour-port} -Bonjour queries in the module manifest can now specify a filter based on port number. +Bonjour queries in the module manifest can now specify a filter based on port +number. ## New utility methods for escape character handling {#utility-methods} diff --git a/for-developers/module-development/api-changes/v1.13.md b/for-developers/module-development/api-changes/v1.13.md index b3edfa8..7ba0ea9 100644 --- a/for-developers/module-development/api-changes/v1.13.md +++ b/for-developers/module-development/api-changes/v1.13.md @@ -5,9 +5,12 @@ sidebar_position: -113 ## Variables in `textinput` fields are now automatically parsed {#variable-parsing} -You no longer need to call `parseVariablesInString` in most circumstances. Any `textinput` field with `useVariables` defined will automatically have variables parsed before the action/feedback is called. +You no longer need to call `parseVariablesInString` in most circumstances. Any +`textinput` field with `useVariables` defined will automatically have variables +parsed before the action/feedback is called. -Any `parseVariablesInString` calls you are doing on these fields is now a no-op and can be removed. +Any `parseVariablesInString` calls you are doing on these fields is now a no-op +and can be removed. :::note @@ -17,31 +20,44 @@ If you are parsing any non textinput fields, these will not be auto-parsed. :::tip -This is groundwork to better allow us to handle expressions for you, expect more to change around this in future releases. +This is groundwork to better allow us to handle expressions for you, expect more +to change around this in future releases. ::: ## Value-type feedbacks (support for local variables) {#value-feedbacks} -As part of the new local variables support in Companion, you can now define `value` feedbacks. These are similar to `boolean` feedbacks, but you can return any type of value. +As part of the new local variables support in Companion, you can now define +`value` feedbacks. These are similar to `boolean` feedbacks, but you can return +any type of value. -Within Companion, the user is able to store the value you provide into a local variable. They can also do this with `boolean` feedbacks, but `boolean` feedbacks can also be used directly in styling a button, a `value` feedback cannot +Within Companion, the user is able to store the value you provide into a local +variable. They can also do this with `boolean` feedbacks, but `boolean` +feedbacks can also be used directly in styling a button, a `value` feedback +cannot ## `options:` improvements: new `description` field; multiline `textinput` field; "infinity" bounds for `number` fields {#new-options} -Every field can now specify a `description`. This is intended to be a some hint to the user that should always be visible, and gets shown below the input field. +Every field can now specify a `description`. This is intended to be a some hint +to the user that should always be visible, and gets shown below the input field. -The `textinput` field type can now request to be multiline. This will provide a single string, with `\n` characters where the user added a line break +The `textinput` field type can now request to be multiline. This will provide a +single string, with `\n` characters where the user added a line break -The `number` field type can opt to show the defined min or max values as infinity. This is common behaviour for audio mixers, where they treat some low value such as -90 as -infinity +The `number` field type can opt to show the defined min or max values as +infinity. This is common behaviour for audio mixers, where they treat some low +value such as -90 as -infinity ## `secret-text` field-type for Configs {#secrets} -There is a new `secret-text` field type available to the connection config panel. +There is a new `secret-text` field type available to the connection config +panel. -This is intended to allow for us to better track what config values are secret and might want to be omitted from some exports. +This is intended to allow for us to better track what config values are secret +and might want to be omitted from some exports. -These get provided to your module as another parameter to the `init` and `configUpdated` methods. +These get provided to your module as another parameter to the `init` and +`configUpdated` methods. :::tip @@ -51,8 +67,12 @@ Make sure to not mix them, or it defeats the purpose of them being separate ## subscribe/unsubscribe: More flexibility for actions / less for feedbacks {#subscribe} -Actions can opt out of their unsubscribe method being called when the options change. +Actions can opt out of their unsubscribe method being called when the options +change. -They can also specify which options should not trigger a call to subscribe/unsubscribe, allowing you to filter out noisy/excessive calls. +They can also specify which options should not trigger a call to +subscribe/unsubscribe, allowing you to filter out noisy/excessive calls. -Feedback subscribe/unsubscribe callbacks are no longer called for every options change, as this happens every time the options or a variable inside the options changes. +Feedback subscribe/unsubscribe callbacks are no longer called for every options +change, as this happens every time the options or a variable inside the options +changes. diff --git a/for-developers/module-development/api-changes/v1.14.md b/for-developers/module-development/api-changes/v1.14.md index 1379fc6..c40749c 100644 --- a/for-developers/module-development/api-changes/v1.14.md +++ b/for-developers/module-development/api-changes/v1.14.md @@ -6,11 +6,17 @@ description: Config layout changes, Connection processes now include the label ## Automated layout for Config parameters {#config-layout} -The connection config panel allowed modules to customise the layout of input fields. This was not possible elsewhere in Companion, and is inconsistent with elsewhere within the panel where fields are in the simplified layout. +The connection config panel allowed modules to customise the layout of input +fields. This was not possible elsewhere in Companion, and is inconsistent with +elsewhere within the panel where fields are in the simplified layout. -As of @companion-module/base v1.14, modules will now be presented in this consistent layout. Modules using older versions of the API will not be affected, until they update. +As of @companion-module/base v1.14, modules will now be presented in this +consistent layout. Modules using older versions of the API will not be affected, +until they update. -It is our hope that this new layout will not cause significant issues, if you have any problems or really dislike it, you can temporarily opt out of the new layout by adding to your module constructor: +It is our hope that this new layout will not cause significant issues, if you +have any problems or really dislike it, you can temporarily opt out of the new +layout by adding to your module constructor: ```js this.instanceOptions.disableNewConfigLayout = true @@ -22,10 +28,14 @@ This is a temporary opt out, in a few releases time it will be removed. ::: -Let us know if there is extra configurability that you need, we are open to restoring any needed functionality that is lost. +Let us know if there is extra configurability that you need, we are open to +restoring any needed functionality that is lost. -See the [PR](https://github.com/bitfocus/companion/pull/3569) for more examples on the impact. +See the [PR](https://github.com/bitfocus/companion/pull/3569) for more examples +on the impact. ## Connection processes now include the label (name) of the connection {#connection-process-name} -To improve the developer experience, when looking at each process in task manager or activity monitor, each process is now labelled with the label of the connection. +To improve the developer experience, when looking at each process in task +manager or activity monitor, each process is now labelled with the label of the +connection. diff --git a/for-developers/module-development/api-changes/v1.5.md b/for-developers/module-development/api-changes/v1.5.md index e74401f..140aa2b 100644 --- a/for-developers/module-development/api-changes/v1.5.md +++ b/for-developers/module-development/api-changes/v1.5.md @@ -5,13 +5,17 @@ sidebar_position: -105 ## Automatic invert property for boolean feedbacks {#feedback-invert} -Boolean feedbacks now automatically get an 'inverted' property added by Companion. +Boolean feedbacks now automatically get an 'inverted' property added by +Companion. :::tip -If you already have an option performing a similar job, we recommend using an upgrade script to move its value into our field and remove the option. -Alternatively, you can opt out of our field, but be aware that users may have already set values that you should try to preserve +If you already have an option performing a similar job, we recommend using an +upgrade script to move its value into our field and remove the option. +Alternatively, you can opt out of our field, but be aware that users may have +already set values that you should try to preserve ::: -If we detect that your feedback already has an invert field, we will hide and disable ours, but this doesn't find every field +If we detect that your feedback already has an invert field, we will hide and +disable ours, but this doesn't find every field diff --git a/for-developers/module-development/api-changes/v1.7.md b/for-developers/module-development/api-changes/v1.7.md index 902346f..b48717a 100644 --- a/for-developers/module-development/api-changes/v1.7.md +++ b/for-developers/module-development/api-changes/v1.7.md @@ -7,8 +7,10 @@ sidebar_position: -107 Many devices use Bonjour or MDNS for discovery. -There is a new `bonjour-device` config field type that you can use to easily perform this discovery for your users as they open the configuration panel. +There is a new `bonjour-device` config field type that you can use to easily +perform this discovery for your users as they open the configuration panel. ## Hex color format and alpha channel support {#color-picker} -The `color` input field type now supports providing colors as `#000000` format hex strings, and can have alpha support enabled +The `color` input field type now supports providing colors as `#000000` format +hex strings, and can have alpha support enabled diff --git a/for-developers/module-development/api-changes/v1.8.md b/for-developers/module-development/api-changes/v1.8.md index d470405..d1255a6 100644 --- a/for-developers/module-development/api-changes/v1.8.md +++ b/for-developers/module-development/api-changes/v1.8.md @@ -5,28 +5,44 @@ sidebar_position: -108 ## Text preset type for organizing presets with headings {#text-presets} -A new 'text' preset type has been added, to allow you to put some headings and blocks of text into the presets panel. +A new 'text' preset type has been added, to allow you to put some headings and +blocks of text into the presets panel. -These will also split the presets into chunks around them, allowing you to organise presets better. +These will also split the presets into chunks around them, allowing you to +organise presets better. ## Support for button-scoped local variables {#local-variables} :::tip -Newer versions of the API replace this with other ways of achieving the same result. Only follow this if you can't update to those +Newer versions of the API replace this with other ways of achieving the same +result. Only follow this if you can't update to those ::: -Companion has added a few variables under the `$(this:XX)` naming. (Since this release, user defined `$(local:XX)` also exist, which need the same support) +Companion has added a few variables under the `$(this:XX)` naming. (Since this +release, user defined `$(local:XX)` also exist, which need the same support) -Due to the way the `parseVariablesInString` method works, Companion often doesn't know what button a string is being parsed for, so can't support variables scoped to a single button. +Due to the way the `parseVariablesInString` method works, Companion often +doesn't know what button a string is being parsed for, so can't support +variables scoped to a single button. -In order to support these, in your action/feedback callback, there is a second `context` parameter which holds an alternate `parseVariablesInString` implementation. This implementation is specific to that callback, so Companion knows what control it belongs to, and can handle the variables. -Additionally, you can indicate that you are doing this and support these variables by setting the `useVariables` property to an object like `{ local: true }` to indicate this support. This allows us to show a hint to the user about this support, and suggest the available variables whilst they type. +In order to support these, in your action/feedback callback, there is a second +`context` parameter which holds an alternate `parseVariablesInString` +implementation. This implementation is specific to that callback, so Companion +knows what control it belongs to, and can handle the variables. Additionally, +you can indicate that you are doing this and support these variables by setting +the `useVariables` property to an object like `{ local: true }` to indicate this +support. This allows us to show a hint to the user about this support, and +suggest the available variables whilst they type. ## Shared UDP port listener for devices with hardcoded ports {#shared-udp} -A few devices have been found which are not cooperative when it comes to control, and expect to send all messages to a hardcoded UDP port. -This makes it hard to support these, as by default only one connection can listen on a port at a time. +A few devices have been found which are not cooperative when it comes to +control, and expect to send all messages to a hardcoded UDP port. This makes it +hard to support these, as by default only one connection can listen on a port at +a time. -To help with this, Companion offers some Shared UDP listener utils, where Companion will open and manage the port for you, and you can simply receive all messages sent to it. +To help with this, Companion offers some Shared UDP listener utils, where +Companion will open and manage the port for you, and you can simply receive all +messages sent to it. diff --git a/for-developers/module-development/api-changes/v2.0.md b/for-developers/module-development/api-changes/v2.0.md index 3efb03d..357bed7 100644 --- a/for-developers/module-development/api-changes/v2.0.md +++ b/for-developers/module-development/api-changes/v2.0.md @@ -1,44 +1,58 @@ --- title: API 2.0 (Companion 4.3+) sidebar_position: -200 -description: 'Overview of API 2.0 breaking changes (expression parsing, presets overhaul, TypeScript improvements).' +description: 'Overview of API 2.0 breaking changes (expression parsing, presets overhaul, + TypeScript improvements).' --- :::warning This version is still a draft and is not finalised yet -Feel free to give this a read to prepare yourself for what is coming. It is not too late to give feedback! +Feel free to give this a read to prepare yourself for what is coming. It is not +too late to give feedback! ::: -This is a major series of changes — the first breaking changes since Companion 3.0, over three years in the making. +This is a major series of changes — the first breaking changes since Companion +3.0, over three years in the making. -If you are not ready to tackle these changes, there is no rush. Many of the changes improve module functionality, but API 1.x remains fully supported and there are no plans to remove that support. +If you are not ready to tackle these changes, there is no rush. Many of the +changes improve module functionality, but API 1.x remains fully supported and +there are no plans to remove that support. ## Required changes ### Dropping support for Node 18 -Node 18 stopped receiving security updates in early 2025, so we will not support it for API 2.0. +Node 18 stopped receiving security updates in early 2025, so we will not support +it for API 2.0. -This also allows us to use newer language and platform features and to clean up the dependency tree. +This also allows us to use newer language and platform features and to clean up +the dependency tree. -If your module is set to use the `node18` runtime in its manifest, it will need to be updated to `node22`. +If your module is set to use the `node18` runtime in its manifest, it will need +to be updated to `node22`. ### @companion-module/base is now ESM -As part of dropping support for Node 18, this library is now written in the newer ESM syntax. For TypeScript users, update your `tsconfig` to use `"moduleResolution": "nodenext"`, or, if using our tsconfig presets, extend `@companion-module/tools/tsconfig/node22/recommended-esm`. +As part of dropping support for Node 18, this library is now written in the +newer ESM syntax. For TypeScript users, update your `tsconfig` to use +`"moduleResolution": "nodenext"`, or, if using our tsconfig presets, extend +`@companion-module/tools/tsconfig/node22/recommended-esm`. :::tip -For most modules this will have no impact; you shouldn't need to change a JavaScript module. +For most modules this will have no impact; you shouldn't need to change a +JavaScript module. ::: ### Remove `runEntrypoint` method -The `runEntrypoint` method has been removed. Instead, change your main/default file to use a default export. Additionally, any upgrade scripts should be exported as a named `UpgradeScripts` constant. +The `runEntrypoint` method has been removed. Instead, change your main/default +file to use a default export. Additionally, any upgrade scripts should be +exported as a named `UpgradeScripts` constant. #### Before: @@ -68,9 +82,11 @@ TODO: test this ### Required manifest type property -To help us differentiate connection modules from surface modules, modules must now add a `"type": "connection"` to their `companion/manifest.json`. +To help us differentiate connection modules from surface modules, modules must +now add a `"type": "connection"` to their `companion/manifest.json`. -If you don't already, we also recommend defining the `$schema` property to give your editor suggestions. +If you don't already, we also recommend defining the `$schema` property to give +your editor suggestions. ```json { @@ -82,68 +98,101 @@ If you don't already, we also recommend defining the `$schema` property to give ### Additional runtime checks for modules -To help with the migration to the new API, Companion performs additional checks on your module and writes warnings to the module debug log. Keep an eye on these messages — Companion acts as a helpful second pair of eyes for things you may have missed. +To help with the migration to the new API, Companion performs additional checks +on your module and writes warnings to the module debug log. Keep an eye on these +messages — Companion acts as a helpful second pair of eyes for things you may +have missed. ## Automatic expression parsing -One of the most requested features in Companion has been using variables in every action or feedback field. More recently, support for expressions has also been requested. +One of the most requested features in Companion has been using variables in +every action or feedback field. More recently, support for expressions has also +been requested. -This has been challenging because it requires changes to upgrade scripts and may break assumptions modules have made about options. It also risks degrading the user experience for fields that expect specific values. +This has been challenging because it requires changes to upgrade scripts and may +break assumptions modules have made about options. It also risks degrading the +user experience for fields that expect specific values. -Because of this, only modules updated to API 2.0 will have expression support, so we can be confident modules won't break. +Because of this, only modules updated to API 2.0 will have expression support, +so we can be confident modules won't break. ### The `parseVariablesInString` method has been removed -Companion now automatically parses variables in input fields according to the option definitions and whether the field is in expression mode. +Companion now automatically parses variables in input fields according to the +option definitions and whether the field is in expression mode. See below for details on how expressions are handled in options. -We believe there is no longer any reason to call `parseVariablesInString` directly, so it has been removed. If you have a valid use case, please let us know, we are open to restoring it. +We believe there is no longer any reason to call `parseVariablesInString` +directly, so it has been removed. If you have a valid use case, please let us +know, we are open to restoring it. ### Expression handling in options -As part of automatic parsing, Companion also executes expressions in action and feedback options. +As part of automatic parsing, Companion also executes expressions in action and +feedback options. Currently this applies to each field you define when: -- When a field is of type `textinput` and has `useVariables: true`, variables will be parsed -- Any field that does not have `disableAutoExpression` enabled and that the user has toggled into expression mode +- When a field is of type `textinput` and has `useVariables: true`, variables + will be parsed +- Any field that does not have `disableAutoExpression` enabled and that the user + has toggled into expression mode -When executing expressions in option values, Companion will ensure the computed value is valid according to the field definition. This means: +When executing expressions in option values, Companion will ensure the computed +value is valid according to the field definition. This means: -- For a `number` field, the value will be clamped to the `min` and `max` you provide -- For a `dropdown` field, the value must be a valid option (unless `useCustom: true`, in which case any string is accepted) +- For a `number` field, the value will be clamped to the `min` and `max` you + provide +- For a `dropdown` field, the value must be a valid option (unless + `useCustom: true`, in which case any string is accepted) - Similar behaviour applies to other field types -If this validation fails and we can't auto-correct it (eg clamping the number), then the action or feedback will be skipped, as if it was disabled. -We do this so you don't receive values you are unprepared to handle. However, sometimes you may want to accept any value (for example, your callback may interpret `1` and `'ch1'` both as `1`). By setting `allowInvalidValues: true` on the option field, you will receive these non-standard values. +If this validation fails and we can't auto-correct it (eg clamping the number), +then the action or feedback will be skipped, as if it was disabled. We do this +so you don't receive values you are unprepared to handle. However, sometimes you +may want to accept any value (for example, your callback may interpret `1` and +`'ch1'` both as `1`). By setting `allowInvalidValues: true` on the option field, +you will receive these non-standard values. -Some options don't make sense as expressions — for example, an option that chooses between `on`/`off`/`toggle`. Set `disableAutoExpression: true` on the field to disable expression support for that field. +Some options don't make sense as expressions — for example, an option that +chooses between `on`/`off`/`toggle`. Set `disableAutoExpression: true` on the +field to disable expression support for that field. :::tip -You can set an `expressionDescription` to show guidance beneath the expression input field explaining what values are valid. +You can set an `expressionDescription` to show guidance beneath the expression +input field explaining what values are valid. ::: -If you use `subscribe` or `unsubscribe` on actions, consider setting the `optionsToMonitorForSubscribe` property to avoid unnecessary calls when unrelated options change. Some values may change multiple times per second and cause extra work for your module. +If you use `subscribe` or `unsubscribe` on actions, consider setting the +`optionsToMonitorForSubscribe` property to avoid unnecessary calls when +unrelated options change. Some values may change multiple times per second and +cause extra work for your module. ### Using sensible values for options -Now that many fields can be toggled into expressions by the user, take a moment to consider if the values used by any dropdown fields are user friendly. +Now that many fields can be toggled into expressions by the user, take a moment +to consider if the values used by any dropdown fields are user friendly. -Many modules are using values here that make sense for how they talk to the device, but are not at all user friendly. Some examples: +Many modules are using values here that make sense for how they talk to the +device, but are not at all user friendly. Some examples: - Some modules are embedding osc path fragments - Some are doing channel1=0, channel2=1 -Consider that the user will need to remember and write these. They will appreciate obvious and simple values. +Consider that the user will need to remember and write these. They will +appreciate obvious and simple values. -If you want to be really friendly, you could use `allowInvalidValues: true` and try to be tolerant of typos. +If you want to be really friendly, you could use `allowInvalidValues: true` and +try to be tolerant of typos. :::tip -Now is the best time to address these, as you can assume that your upgrade script won't need to handle any expression values. If you do it later, you will need to handle expressions which are hiding the values being provided. +Now is the best time to address these, as you can assume that your upgrade +script won't need to handle any expression values. If you do it later, you will +need to handle expressions which are hiding the values being provided. ::: @@ -151,13 +200,18 @@ Now is the best time to address these, as you can assume that your upgrade scrip :::warning -This expression support introduces a breaking change for existing upgrade scripts. +This expression support introduces a breaking change for existing upgrade +scripts. ::: -Unfortunately, expression support means your upgrade scripts must be prepared for any field to be an expression. Because we cannot know whether an upgrade script was written before or after expression support, we require all upgrade scripts to handle the new shape for all inputs. +Unfortunately, expression support means your upgrade scripts must be prepared +for any field to be an expression. Because we cannot know whether an upgrade +script was written before or after expression support, we require all upgrade +scripts to handle the new shape for all inputs. -The key change is the shape of the `options` object. Previously you might have received: +The key change is the shape of the `options` object. Previously you might have +received: ```js options: { @@ -175,19 +229,25 @@ options: { } ``` -In future updates to your module some of those could be expressions, for example: +In future updates to your module some of those could be expressions, for +example: ```js a: { isExpression: true, value: "$(local:a) + 1" } ``` -Going forward, upgrade scripts must handle this new shape. You can safely assume that any upgrade scripts you write during this update (or prior) will not encounter `isExpression: true` for existing stored values. When writing future upgrade scripts, review the docs on upgrade scripts for advice on handling the new format. +Going forward, upgrade scripts must handle this new shape. You can safely assume +that any upgrade scripts you write during this update (or prior) will not +encounter `isExpression: true` for existing stored values. When writing future +upgrade scripts, review the docs on upgrade scripts for advice on handling the +new format. For feedbacks, the `isInverted` property now uses the same shaped object. #### Real example -Below is a real-world upgrade script pattern demonstrating how to walk actions/feedbacks and update numeric options while preserving expressions. +Below is a real-world upgrade script pattern demonstrating how to walk +actions/feedbacks and update numeric options while preserving expressions. ```js /** @@ -241,48 +301,74 @@ See the upgrade-scripts documentation for more patterns and helpers. ### Recommended cleanup for expressions -For years many modules performed their own variable parsing in action and feedback fields. Now that any field can be an expression, some options would benefit from clearer field types or removal of duplicate actions/feedbacks. +For years many modules performed their own variable parsing in action and +feedback fields. Now that any field can be an expression, some options would +benefit from clearer field types or removal of duplicate actions/feedbacks. -Cleaning up now improves the user experience by reducing confusion and providing better hints about valid values. +Cleaning up now improves the user experience by reducing confusion and providing +better hints about valid values. -For example, if you have number fields implemented as `textinput` so users could type variables, change them to a `number` field and use an upgrade script to convert previous inputs to expressions. We provide a helper `FixupNumericOrVariablesValueToExpressions`: +For example, if you have number fields implemented as `textinput` so users could +type variables, change them to a `number` field and use an upgrade script to +convert previous inputs to expressions. We provide a helper +`FixupNumericOrVariablesValueToExpressions`: ```js -const result1 = FixupNumericOrVariablesValueToExpressions({ isExpression: false, value: '1' }) +const result1 = FixupNumericOrVariablesValueToExpressions({ + isExpression: false, + value: '1', +}) // returns: { isExpression: false, value: 1 } -const result2 = FixupNumericOrVariablesValueToExpressions({ isExpression: false, value: '$(local:abc)' }) +const result2 = FixupNumericOrVariablesValueToExpressions({ + isExpression: false, + value: '$(local:abc)', +}) // returns: { isExpression: true, value: '$(local:abc)' } -const result3 = FixupNumericOrVariablesValueToExpressions({ isExpression: false, value: '$(local:abc)$(local:def)' }) +const result3 = FixupNumericOrVariablesValueToExpressions({ + isExpression: false, + value: '$(local:abc)$(local:def)', +}) // returns: { isExpression: true, value: 'parseVariables("$(local:abc)$(local:def)")' } ``` :::tip -Doing this cleanup now is easier than doing it later, since you don't yet need to handle stored `isExpression: true` values. +Doing this cleanup now is easier than doing it later, since you don't yet need +to handle stored `isExpression: true` values. ::: ### Referencing expressions from `isVisibleExpression -When a field's value comes from an expression, you cannot reference it from another field in an `isVisibleExpression`. +When a field's value comes from an expression, you cannot reference it from +another field in an `isVisibleExpression`. -We disallow this because it can lead to fields being hidden when they are actually needed later as the computed expression value changes, which would confuse users and prevent them from editing required fields. +We disallow this because it can lead to fields being hidden when they are +actually needed later as the computed expression value changes, which would +confuse users and prevent them from editing required fields. ## Presets overhaul -Presets have been reorganised in this release to make large preset sets easier to manage and display. +Presets have been reorganised in this release to make large preset sets easier +to manage and display. -For some time we've found presets can be repetitive and benefit from additional structure. API 1.8 (Companion 3.3) introduced a `text` preset type to help with layout; the new approach formalises that idea into proper groups. +For some time we've found presets can be repetitive and benefit from additional +structure. API 1.8 (Companion 3.3) introduced a `text` preset type to help with +layout; the new approach formalises that idea into proper groups. ### Overhauling preset definition structure -Some modules have many presets, and categories alone are no longer sufficient to present them clearly. +Some modules have many presets, and categories alone are no longer sufficient to +present them clearly. -Previously some modules used the `text` definition to break large blocks into well-described sections. That structure is now formalised: presets should use a hierarchy of `sections` → `groups` → `definitions`. +Previously some modules used the `text` definition to break large blocks into +well-described sections. That structure is now formalised: presets should use a +hierarchy of `sections` → `groups` → `definitions`. -To support this, `setPresetDefinitions` has been reworked and now expects two parameters: `structure` and `presets`. +To support this, `setPresetDefinitions` has been reworked and now expects two +parameters: `structure` and `presets`. The `presets` parameter should be an object listing preset definitions: @@ -305,13 +391,17 @@ const presets = { :::tip -Make sure to change the `type` property to `simple`. We intend to add additional types in a future release. Also remove the old `category` property. +Make sure to change the `type` property to `simple`. We intend to add additional +types in a future release. Also remove the old `category` property. ::: -Using this object for `presets` lets you define a preset once and reference it in multiple places within the `structure` (see [Preset templating](#preset-templating)). +Using this object for `presets` lets you define a preset once and reference it +in multiple places within the `structure` (see +[Preset templating](#preset-templating)). -The `structure` array describes how to present these presets in the UI. For example: +The `structure` array describes how to present these presets in the UI. For +example: ```js const structure = [ @@ -332,19 +422,24 @@ const structure = [ ] ``` -This replaces the old `category` property that was previously defined on each preset. The new structure lets you present presets with more organisation and give each section or group its own description. +This replaces the old `category` property that was previously defined on each +preset. The new structure lets you present presets with more organisation and +give each section or group its own description. -If you were using the `text` definition type before, replace those entries with groups. +If you were using the `text` definition type before, replace those entries with +groups. :::tip -More group types are supported — see [Preset templating](#preset-templating) for details. +More group types are supported — see [Preset templating](#preset-templating) for +details. ::: ### Local variables in presets -Companion 4.1 added support for user-defined local variables. While actions and feedbacks could already use these variables, presets could not define them. +Companion 4.1 added support for user-defined local variables. While actions and +feedbacks could already use these variables, presets could not define them. Presets can now declare 'user value' local variables: @@ -358,11 +453,13 @@ localVariables: [ ], ``` -This makes presets easier for users to edit by providing a single place to adjust values instead of editing multiple actions and feedbacks. +This makes presets easier for users to edit by providing a single place to +adjust values instead of editing multiple actions and feedbacks. :::tip -This pairs nicely with the `template` preset group, enabling simple templating within presets. +This pairs nicely with the `template` preset group, enabling simple templating +within presets. ::: @@ -370,7 +467,8 @@ This pairs nicely with the `template` preset group, enabling simple templating w Modules often produce many similar presets that differ only by a few values. -To help, we now support templating in presets via a `template` group type that overrides local variable values. +To help, we now support templating in presets via a `template` group type that +overrides local variable values. For example: @@ -400,7 +498,8 @@ For example: } ``` -Companion will render this in the UI as two presets generated from the template, for example: +Companion will render this in the UI as two presets generated from the template, +for example: ```js { @@ -419,21 +518,27 @@ Companion will render this in the UI as two presets generated from the template, } ``` -We hope this simplifies preset generation logic and reduces presets' data size, improving memory usage and performance in Companion. +We hope this simplifies preset generation logic and reduces presets' data size, +improving memory usage and performance in Companion. ### Dropping support for absolute delays in presets -Support for absolute delays in presets has been removed; all preset delays are now interpreted as relative. +Support for absolute delays in presets has been removed; all preset delays are +now interpreted as relative. -This matches Companion's behaviour, which only supports relative delays through the `internal: Wait` action and avoids confusing translations. +This matches Companion's behaviour, which only supports relative delays through +the `internal: Wait` action and avoids confusing translations. ## TypeScript reworking -The TypeScript types in the library have received significant attention to help you strongly type various aspects of your module. +The TypeScript types in the library have received significant attention to help +you strongly type various aspects of your module. ### `InstanceBase` generic change {#instancebase-generic-change} -The `InstanceBase` class remains generic, but it no longer expects a `TConfig`. Instead it expects a type that describes your `config`, `actions`, `feedbacks`, and `variables`. +The `InstanceBase` class remains generic, but it no longer expects a `TConfig`. +Instead it expects a type that describes your `config`, `actions`, `feedbacks`, +and `variables`. If no type is specified, the default is: @@ -459,12 +564,15 @@ or you can write your own from scratch. ### Strongly typed actions and feedbacks -With the generic change on `InstanceBase`, types now propagate through to related types such as: +With the generic change on `InstanceBase`, types now propagate through to +related types such as: - `CompanionActionDefinition` - `CompanionFeedbackDefinition` -On the `InstanceBase` class, the definition of `setActionDefinitions` (and similar methods) will now match the types you declare in your `InstanceTypes`, providing stronger typing and better IDE assistance. +On the `InstanceBase` class, the definition of `setActionDefinitions` (and +similar methods) will now match the types you declare in your `InstanceTypes`, +providing stronger typing and better IDE assistance. For example: @@ -487,27 +595,35 @@ const act: CompanionActionDefinition<{ num: number }> = { } ``` -In this example TypeScript knows that `event.options.num` is a number and that a value such as `event.options.other` does not exist. +In this example TypeScript knows that `event.options.num` is a number and that a +value such as `event.options.other` does not exist. :::tip -You need to ensure that the generic and your option types match; we cannot do that automatically. +You need to ensure that the generic and your option types match; we cannot do +that automatically. ::: -Combined with the [Automatic expression parsing](#automatic-expression-parsing), this should ensure that the types you declare are what you actually receive and can tidy up a lot of logic. +Combined with the [Automatic expression parsing](#automatic-expression-parsing), +this should ensure that the types you declare are what you actually receive and +can tidy up a lot of logic. -`InstanceTypes` also defines variables, which is propagated and gives you type hints when updating variable values. +`InstanceTypes` also defines variables, which is propagated and gives you type +hints when updating variable values. ## Miscellaneous changes ### New logging utility -To improve logging in your module, you can now produce a full range of log levels without passing around your class instance. +To improve logging in your module, you can now produce a full range of log +levels without passing around your class instance. -Loggers created this way work from anywhere in your module and route to the same destination as the instance methods. +Loggers created this way work from anywhere in your module and route to the same +destination as the instance methods. -These loggers can be created with an optional prefix, which appears in the log output and helps produce structured logs. +These loggers can be created with an optional prefix, which appears in the log +output and helps produce structured logs. ```ts import { createModuleLogger } from '@companion-module/base' @@ -519,19 +635,27 @@ logger.error('something happened!') ### Control over UI order of actions and feedbacks -Companion sorts your action and feedback definitions by name when displaying them to the user. +Companion sorts your action and feedback definitions by name when displaying +them to the user. -If this is undesirable, a new `sortName` property allows you to control sorting. When set, `sortName` is used instead of `name`; its value is not shown to users. +If this is undesirable, a new `sortName` property allows you to control sorting. +When set, `sortName` is used instead of `name`; its value is not shown to users. ### Clarifying `this.checkFeedbacks()` usage -In very old versions of Companion, it was expected that modules should call `this.checkFeedbacks()` without any arguments in order to trigger a check of all the feedbacks. +In very old versions of Companion, it was expected that modules should call +`this.checkFeedbacks()` without any arguments in order to trigger a check of all +the feedbacks. -Many versions back, it became possible to supply the types of feedbacks as an argument, to allow for only rechecking a subset of the feedbacks upon each call. +Many versions back, it became possible to supply the types of feedbacks as an +argument, to allow for only rechecking a subset of the feedbacks upon each call. -Due to this dual behaviour, it is easy for a module to call `this.checkFeedbacks()` without realising it was bad practice, especially with all the existing code showing exactly that. +Due to this dual behaviour, it is easy for a module to call +`this.checkFeedbacks()` without realising it was bad practice, especially with +all the existing code showing exactly that. -To clarify the intended usage, this older behaviour has been removed. With a new `this.checkAllFeedbacks()` method being added instead. +To clarify the intended usage, this older behaviour has been removed. With a new +`this.checkAllFeedbacks()` method being added instead. ```ts // before @@ -546,56 +670,77 @@ this.checkFeedbacks('my-feedback') :::tip -We strongly recommend using `checkFeedbacks` with one or more arguments whenever possible, as it reduces the amount of work your module will do whenever a feedback changes +We strongly recommend using `checkFeedbacks` with one or more arguments whenever +possible, as it reduces the amount of work your module will do whenever a +feedback changes ::: -Usages of `this.checkFeedbacksById(...)` are unaffected by this change, and remain valid. +Usages of `this.checkFeedbacksById(...)` are unaffected by this change, and +remain valid. ### Feedback lifecycle simplification -Because Companion now automatically parses variables in feedback options, the `subscribe` method became confusing: any option change could trigger `unsubscribe`, `subscribe`, and `callback` in sequence. +Because Companion now automatically parses variables in feedback options, the +`subscribe` method became confusing: any option change could trigger +`unsubscribe`, `subscribe`, and `callback` in sequence. -The lifecycle has been simplified by removing `subscribe` and simplifying when `unsubscribe` is called. +The lifecycle has been simplified by removing `subscribe` and simplifying when +`unsubscribe` is called. -Now, `callback` is invoked whenever the feedback should run and is the only method called when the feedback is added or its options are updated. -`unsubscribe` is called only when the user deletes or disables the feedback, allowing you to do cleanup when the feedback becomes inactive. +Now, `callback` is invoked whenever the feedback should run and is the only +method called when the feedback is added or its options are updated. +`unsubscribe` is called only when the user deletes or disables the feedback, +allowing you to do cleanup when the feedback becomes inactive. -To help track state, `previousOptions` is now provided to the `callback`. This contains the values from the previous call so you can detect relevant changes without tracking state yourself. +To help track state, `previousOptions` is now provided to the `callback`. This +contains the values from the previous call so you can detect relevant changes +without tracking state yourself. ### Learn callback return value changes -If you implement a `learn` callback in your actions or feedbacks, expectations for its return value have changed. +If you implement a `learn` callback in your actions or feedbacks, expectations +for its return value have changed. -Previously you were expected to return all options; now you should only return the options being "learnt" in this call. +Previously you were expected to return all options; now you should only return +the options being "learnt" in this call. -If you continue returning all options you may overwrite expressions the user has entered in other fields. +If you continue returning all options you may overwrite expressions the user has +entered in other fields. ### Replace action `optionsToIgnoreForSubscribe` with `optionsToMonitorForSubscribe` -As part of the expression changes, `optionsToIgnoreForSubscribe` has been replaced with an allowlist `optionsToMonitorForSubscribe`. +As part of the expression changes, `optionsToIgnoreForSubscribe` has been +replaced with an allowlist `optionsToMonitorForSubscribe`. -This reduces the chance of forgetting to update it when you add new options. When not set, it is treated as if all options are monitored. +This reduces the chance of forgetting to update it when you add new options. +When not set, it is treated as if all options are monitored. ### Replacing `required` property on some option field types The `required` property has been unclear for some time. -Instead, the `textinput` field now supports a `minLength` property, which offers similar behaviour but greater control. +Instead, the `textinput` field now supports a `minLength` property, which offers +similar behaviour but greater control. ### Bonjour query IPv6 support -Bonjour queries can now opt into IPv6 support by setting the `addressFamily` field in a query. This can be `ipv4`, `ipv6`, or `ipv4+6`. +Bonjour queries can now opt into IPv6 support by setting the `addressFamily` +field in a query. This can be `ipv4`, `ipv6`, or `ipv4+6`. ### Convert 'isVisible' functions to 'isVisibleExpression'. -Since API 1.12 (Companion 4.0), it has been possible to define `isVisible` expressions using the `isVisibleExpression` property. +Since API 1.12 (Companion 4.0), it has been possible to define `isVisible` +expressions using the `isVisibleExpression` property. -The old function-based `isVisible` approach is no longer supported and will be ignored. +The old function-based `isVisible` approach is no longer supported and will be +ignored. :::tip -When used in actions or feedbacks, expressions are only allowed to reference fields that cannot be an expression. See [Automatic expression parsing](#automatic-expression-parsing) for more details. +When used in actions or feedbacks, expressions are only allowed to reference +fields that cannot be an expression. See +[Automatic expression parsing](#automatic-expression-parsing) for more details. ::: diff --git a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md index 1499406..ce5df16 100644 --- a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md +++ b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md @@ -7,7 +7,9 @@ description: How to set up Bonjour Device Discovery in the user configuration. Bonjour is a standardised method of device discovery, utilising MDNS. -Starting with [API 1.7](../api-changes/v1.7.md) (Companion 3.2), Companion allows you to easily discover devices using the Bonjour protocol, thus helping users with configuration. +Starting with [API 1.7](../api-changes/v1.7.md) (Companion 3.2), Companion +allows you to easily discover devices using the Bonjour protocol, thus helping +users with configuration. ## Setting up Bonjour @@ -36,13 +38,14 @@ and in your `companion/manifest.json`: } ``` -These two structures are linked by the common id, in the future this will allow us to automate device discovery further. +These two structures are linked by the common id, in the future this will allow +us to automate device discovery further. -In the UI, this field will look like: -![image](../images/bonjour.png) +In the UI, this field will look like: ![image](../images/bonjour.png) -The 'Manual' option is always shown, and must be handled to allow users to manually specify an address for environments where Bonjour does not work. -This can be achieved with further config fields such as: +The 'Manual' option is always shown, and must be handled to allow users to +manually specify an address for environments where Bonjour does not work. This +can be achieved with further config fields such as: ```js { @@ -55,20 +58,30 @@ This can be achieved with further config fields such as: }, ``` -Note the presence of the `isVisibleExpression`, to control the visibility of the fields depending on whether a bonjour discovered device has been selected. +Note the presence of the `isVisibleExpression`, to control the visibility of the +fields depending on whether a bonjour discovered device has been selected. -In your module code, the `bonjour_host` will have a value such as `10.0.0.1:8000` or null. +In your module code, the `bonjour_host` will have a value such as +`10.0.0.1:8000` or null. ### Writing your Bonjour Query -We currently support a subset of the possible query options. In all queries, the `type` and `protocol` must be set. -If your device needs further filtering, this can be done by specifying any `txt` field values the entries must have. +We currently support a subset of the possible query options. In all queries, the +`type` and `protocol` must be set. If your device needs further filtering, this +can be done by specifying any `txt` field values the entries must have. -Since [API 1.10](../api-changes/v1.10.md) each entry in the manifest under `bonjourQueries` can be an array, to allow you to run multiple queries in parallel. This can be useful when supporting multiple models which use slightly different queries +Since [API 1.10](../api-changes/v1.10.md) each entry in the manifest under +`bonjourQueries` can be an array, to allow you to run multiple queries in +parallel. This can be useful when supporting multiple models which use slightly +different queries -Since [API 1.12](../api-changes/v1.12.md) it is possible to filter by `port` number in the query. It is recommended to only use this as a last resort, as port numbers are often configurable. +Since [API 1.12](../api-changes/v1.12.md) it is possible to filter by `port` +number in the query. It is recommended to only use this as a last resort, as +port numbers are often configurable. -Since [API 2.0](../api-changes/v2.0.md) it is possible to specify an `addressFamily` for the query. This allows you to specify whether `ipv4`, `ipv6` or both (`ipv4+6`) addresses are returned by the query. +Since [API 2.0](../api-changes/v2.0.md) it is possible to specify an +`addressFamily` for the query. This allows you to specify whether `ipv4`, `ipv6` +or both (`ipv4+6`) addresses are returned by the query. ## Further Reading diff --git a/for-developers/module-development/connection-advanced/http-handler.md b/for-developers/module-development/connection-advanced/http-handler.md index 2bebb00..f330d2f 100644 --- a/for-developers/module-development/connection-advanced/http-handler.md +++ b/for-developers/module-development/connection-advanced/http-handler.md @@ -5,19 +5,38 @@ sidebar_position: 4 description: How to set up HTTP handling for your module. --- -Companion's webserver that serves the Web UI also provides a path for each connection so that HTTP requests can be passed through to an instance of a module. Your module can then choose to respond or otherwise Companion will automatically respond with a 404. The path to an instance will be `/instance/INSTANCE NAME/`, so for example if a user has Companion on `http://127.0.0.1:8000/` and creates a Google Sheets connection called 'sheet', HTTP traffic to `http://127.0.0.1:8000/instance/sheet/` will be forwarded to the HTTP handler in Google Sheets for that connection. - -Because each instance acts as a child process of Companion, only a subset of the properties for a HTTP request to Express are passed on to the child processes. This allows for most common usages, but more complex setups such as utilizing the HTTP handler for WebSockets will not work. +Companion's webserver that serves the Web UI also provides a path for each +connection so that HTTP requests can be passed through to an instance of a +module. Your module can then choose to respond or otherwise Companion will +automatically respond with a 404. The path to an instance will be +`/instance/INSTANCE NAME/`, so for example if a user has Companion on +`http://127.0.0.1:8000/` and creates a Google Sheets connection called 'sheet', +HTTP traffic to `http://127.0.0.1:8000/instance/sheet/` will be forwarded to the +HTTP handler in Google Sheets for that connection. + +Because each instance acts as a child process of Companion, only a subset of the +properties for a HTTP request to Express are passed on to the child processes. +This allows for most common usages, but more complex setups such as utilizing +the HTTP handler for WebSockets will not work. A few example use cases for the HTTP handler: -- Expose data generated/collected by the module. For example the Google Sheets module makes all of the spreadsheet data available as both JSON and CSV, this allows apps such as vMix to utilize that as a data source far more efficiently and responsively than if it was to interact with Google Sheets itself. -- Expose some of the functionality of Actions, so if an external device/service needs to be able to run an Action it could be made available to be run directly rather than requiring it placed on a button and then use Companion's API to press/release that button. -- A HTML page that acts as a UI for users, which could even pull data from JSON endpoints to dynamically fill that HTML page with data, and POST endpoints that the page can send requests to for triggering functionality in the module. +- Expose data generated/collected by the module. For example the Google Sheets + module makes all of the spreadsheet data available as both JSON and CSV, this + allows apps such as vMix to utilize that as a data source far more efficiently + and responsively than if it was to interact with Google Sheets itself. +- Expose some of the functionality of Actions, so if an external device/service + needs to be able to run an Action it could be made available to be run + directly rather than requiring it placed on a button and then use Companion's + API to press/release that button. +- A HTML page that acts as a UI for users, which could even pull data from JSON + endpoints to dynamically fill that HTML page with data, and POST endpoints + that the page can send requests to for triggering functionality in the module. ## API call: handleHttpRequest -The `this.handleHttpRequest` method on the Instance class is what handles HTTP requests being passed from Companion to the module instance. +The `this.handleHttpRequest` method on the Instance class is what handles HTTP +requests being passed from Companion to the module instance. ```js handleHttpRequest(request: CompanionHTTPRequest): CompanionHTTPResponse | Promise { diff --git a/for-developers/module-development/connection-advanced/learn-action-feedback-values.md b/for-developers/module-development/connection-advanced/learn-action-feedback-values.md index bc98411..a49e074 100644 --- a/for-developers/module-development/connection-advanced/learn-action-feedback-values.md +++ b/for-developers/module-development/connection-advanced/learn-action-feedback-values.md @@ -5,15 +5,26 @@ sidebar_position: 5 description: How to set up "learn" functionality in actions and feedbacks. --- -To make it easier for users to configure your actions and feedbacks, you can implement the `learn` callback. This is intended to allow for the options of an action or feedback to be set to match the current state of the device. For example, you can program a `learn` callback to set the value for a "Set-Position" action to set the position of a picture-in-picture to its current location on your device. The callback simply queries the current state of the device and returns the appropriate value, as described below. - -When implemented, a Learn Values button appears in the action or feedback allowing the user to trigger a learn event. +To make it easier for users to configure your actions and feedbacks, you can +implement the `learn` callback. This is intended to allow for the options of an +action or feedback to be set to match the current state of the device. For +example, you can program a `learn` callback to set the value for a +"Set-Position" action to set the position of a picture-in-picture to its current +location on your device. The callback simply queries the current state of the +device and returns the appropriate value, as described below. + +When implemented, a Learn +Values button appears in the action or feedback allowing the user to +trigger a learn event. ![Launcher window](../images/action-learn-button.png) -Implementing this callback is the same for actions and feedbacks, but the parameters do vary a little accordingly. +Implementing this callback is the same for actions and feedbacks, but the +parameters do vary a little accordingly. -For an action which has a single option called `input`, one implementation could look like: +For an action which has a single option called `input`, one implementation could +look like: ```js learn: (event) => { @@ -23,7 +34,10 @@ learn: (event) => { }, ``` -In the call, you are passed the same action/feedback object as you would for other callbacks. The callback should return a similar `event.options` object, containing only the new values. You cannot return an expression in these, only plain values. +In the call, you are passed the same action/feedback object as you would for +other callbacks. The callback should return a similar `event.options` object, +containing only the new values. You cannot return an expression in these, only +plain values. In this example, only the `input` field is updated: @@ -37,13 +51,17 @@ learn: (event) => { :::warning -As of API 2.0, you must only return the 'learnt' options in the result. Returning all options will overwrite any expressions the user may be using, so you should avoid returning fields which are unchanged. +As of API 2.0, you must only return the 'learnt' options in the result. +Returning all options will overwrite any expressions the user may be using, so +you should avoid returning fields which are unchanged. -Prior to API 2.0, it was recommended to include all options in the result, otherwise they would become undefined. +Prior to API 2.0, it was recommended to include all options in the result, +otherwise they would become undefined. ::: -If for some reason you are not able to provide any new values, you can instead return `undefined` to tell Companion to abort this `learn` operation. +If for some reason you are not able to provide any new values, you can instead +return `undefined` to tell Companion to abort this `learn` operation. ```js learn: (event) => { @@ -69,4 +87,7 @@ learn: (event) => { - [Actions](../connection-basics/actions.md) - [Feedbacks](../connection-basics/feedbacks.md) -You can also see the full API specification for [actions](https://bitfocus.github.io/companion-module-base/interfaces/CompanionActionDefinition.html#learn) and [feedbacks](https://bitfocus.github.io/companion-module-base/interfaces/CompanionBooleanFeedbackDefinition.html#learn). +You can also see the full API specification for +[actions](https://bitfocus.github.io/companion-module-base/interfaces/CompanionActionDefinition.html#learn) +and +[feedbacks](https://bitfocus.github.io/companion-module-base/interfaces/CompanionBooleanFeedbackDefinition.html#learn). diff --git a/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md b/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md index b446a37..a1e984e 100644 --- a/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md +++ b/for-developers/module-development/connection-advanced/migrating-legacy-to-boolean-feedbacks.md @@ -7,13 +7,22 @@ description: How to migrate legacy feedbacks to boolean feedbacks. ## Why update your feedbacks? -Since Companion v3, most feedbacks are best defined as 'boolean' feedbacks, as they give the user more flexibility and will end up with a more consistent interface. +Since Companion v3, most feedbacks are best defined as 'boolean' feedbacks, as +they give the user more flexibility and will end up with a more consistent +interface. -Previously, it was up to the module author to decide what properties a feedback should change. This tended to limit feedbacks to changing the background and text colour. But what if the user wants to change a png, or the text? They could ask for that to be possible, but that would likely require the module author to duplicate the feedback with different style options. +Previously, it was up to the module author to decide what properties a feedback +should change. This tended to limit feedbacks to changing the background and +text colour. But what if the user wants to change a png, or the text? They could +ask for that to be possible, but that would likely require the module author to +duplicate the feedback with different style options. -With boolean feedbacks, the module author simply has to make the feedback be a true or false value, and the user can decide what style properties that should change. +With boolean feedbacks, the module author simply has to make the feedback be a +true or false value, and the user can decide what style properties that should +change. -A side-benefit of using boolean feedbacks is that they can be used as conditions in the triggers system. +A side-benefit of using boolean feedbacks is that they can be used as conditions +in the triggers system. ## Steps to migrate to boolean feedbacks @@ -21,8 +30,7 @@ The process may involve a bit of work, but it is pretty straightforward. ### 1. Update feedback definitions -The feedback definitions need updating to the new style. -From: +The feedback definitions need updating to the new style. From: ```javascript feedbacks['set_source'] = { @@ -86,7 +94,8 @@ feedbacks['set_source'] = { ### 2. Update presets -Any presets defined in the module will need to be updated to match the changes in the definition +Any presets defined in the module will need to be updated to match the changes +in the definition From: @@ -146,9 +155,13 @@ To: ### 3. Add an upgrade script -Users will have feedbacks assigned to buttons already, and these will all need updating to the new format. A helper has been added to help with this. +Users will have feedbacks assigned to buttons already, and these will all need +updating to the new format. A helper has been added to help with this. -Quick tip: The script will only be run once, if you want to force it to be run again locally, check the [Testing an upgrade script](../connection-basics/upgrade-scripts.md#testing-an-upgrade-script) guide. +Quick tip: The script will only be run once, if you want to force it to be run +again locally, check the +[Testing an upgrade script](../connection-basics/upgrade-scripts.md#testing-an-upgrade-script) +guide. ```js const upgradeToBooleanFeedbacks = CreateConvertToBooleanFeedbackUpgradeScript({ @@ -160,9 +173,10 @@ const upgradeToBooleanFeedbacks = CreateConvertToBooleanFeedbackUpgradeScript({ runEntrypoint(MyInstance, [myOtherUpgradeScript, upgradeToBooleanFeedbacks]) ``` -This script will handle moving the options properties across to the style object for you. -It handles the most common cases of property naming, which may not match what your module does. -If this is the case, you can customise the behaviour by providing more details: +This script will handle moving the options properties across to the style object +for you. It handles the most common cases of property naming, which may not +match what your module does. If this is the case, you can customise the +behaviour by providing more details: ```js CreateConvertToBooleanFeedbackUpgradeScript({ @@ -177,7 +191,8 @@ CreateConvertToBooleanFeedbackUpgradeScript({ Make sure to test it all thoroughly, then you are done! -Feel free to ask on slack if you have any questions, or anything here doesn't make sense. +Feel free to ask on slack if you have any questions, or anything here doesn't +make sense. ### Further Reading diff --git a/for-developers/module-development/connection-advanced/oauth.md b/for-developers/module-development/connection-advanced/oauth.md index 1970dcf..16060d0 100644 --- a/for-developers/module-development/connection-advanced/oauth.md +++ b/for-developers/module-development/connection-advanced/oauth.md @@ -5,26 +5,35 @@ sidebar_position: 3 description: How to set up Authentication with OAuth in the user configuration. --- -Some modules need to authenticate against an external service or API. -Companion does not currently have native support for OAuth, so modules are required to do the flow manually. +Some modules need to authenticate against an external service or API. Companion +does not currently have native support for OAuth, so modules are required to do +the flow manually. There are two key challenges to using OAuth with Companion: -1. OAuth requires a stable redirect URL, the URL to access Companion can change daily -2. The user needs to fill in various fields then navigate to a URL to begin the authentication. +1. OAuth requires a stable redirect URL, the URL to access Companion can change + daily +2. The user needs to fill in various fields then navigate to a URL to begin the + authentication. -Described below is the current recommended way of supporting OAuth, but many existing modules are not using this. Expect this to be refined in the future, as support is improved. +Described below is the current recommended way of supporting OAuth, but many +existing modules are not using this. Expect this to be refined in the future, as +support is improved. ## Handling the OAuth callback / redirect URL -OAuth needs a stable redirect URL, as it needs to be provided to both Companion and in the application settings you are connecting to. -To aid in this, a small redirector site has been created, which will help abstract this. +OAuth needs a stable redirect URL, as it needs to be provided to both Companion +and in the application settings you are connecting to. To aid in this, a small +redirector site has been created, which will help abstract this. -This is hosted at `https://bitfocus.github.io/companion-oauth/callback`. -By providing your instance id (`this.id`) as the state parameter in the authentication url, the redirect site will help redirect the user to a HTTP handler where you can access the generated authentication code. +This is hosted at `https://bitfocus.github.io/companion-oauth/callback`. By +providing your instance id (`this.id`) as the state parameter in the +authentication url, the redirect site will help redirect the user to a HTTP +handler where you can access the generated authentication code. -To receive the authentication code, you should implement the [handleHttpRequest](./http-handler.md) method, listening for the `/oauth/callback` path. -An implementation can look like: +To receive the authentication code, you should implement the +[handleHttpRequest](./http-handler.md) method, listening for the +`/oauth/callback` path. An implementation can look like: ```js async handleHttpRequest(request) { @@ -79,10 +88,12 @@ async handleHttpRequest(request) { ## Opening the authentication URL -The user needs to open the authentication URL to start the OAuth process. -As some users will be configuring their Companion remotely, you can't rely on being able to automatically open the url for them. +The user needs to open the authentication URL to start the OAuth process. As +some users will be configuring their Companion remotely, you can't rely on being +able to automatically open the url for them. -Most modules currently will put the needed URL in a config field for the user to access, and also write it to the log. Some will also open it automatically. +Most modules currently will put the needed URL in a config field for the user to +access, and also write it to the log. Some will also open it automatically. ## Further Reading diff --git a/for-developers/module-development/connection-advanced/permissions.md b/for-developers/module-development/connection-advanced/permissions.md index 53b6810..525b0b7 100644 --- a/for-developers/module-development/connection-advanced/permissions.md +++ b/for-developers/module-development/connection-advanced/permissions.md @@ -5,10 +5,14 @@ sidebar_position: 10 description: Enable advanced runtime permissions for your module --- -Since [API 1.12](../api-changes/v1.12.md) modules are run with some restrictive permissions applied. The intention here is to limit some of the more dangerous abilities of the nodejs runtime, so that we can warn users about modules which require them. -Think of it as similar to how your phone prompts you to accept a list of permissions when installing an app. +Since [API 1.12](../api-changes/v1.12.md) modules are run with some restrictive +permissions applied. The intention here is to limit some of the more dangerous +abilities of the nodejs runtime, so that we can warn users about modules which +require them. Think of it as similar to how your phone prompts you to accept a +list of permissions when installing an app. -To enable any of these, start by adding to the `runtime` object in your manifest: +To enable any of these, start by adding to the `runtime` object in your +manifest: ```js "permissions": { @@ -18,7 +22,10 @@ To enable any of these, start by adding to the `runtime` object in your manifest :::tip -These permissions are applied during development too. However, when [the debugger](../module-debugging.md#attach-a-debugger) is enabled, the permissions are disabled. Make sure to test the module without the debugger enabled before publishing +These permissions are applied during development too. However, when +[the debugger](../module-debugging.md#attach-a-debugger) is enabled, the +permissions are disabled. Make sure to test the module without the debugger +enabled before publishing ::: @@ -42,7 +49,9 @@ If your module needs to spawn child processes, you will need to add: } ``` -We recommend avoiding using child processes whenever possible, as these will be reported to the user as dangerous, as the spawned process will bypass all of the restrictions we apply to your module. +We recommend avoiding using child processes whenever possible, as these will be +reported to the user as dangerous, as the spawned process will bypass all of the +restrictions we apply to your module. ## Native addons @@ -56,7 +65,8 @@ If your module needs to use any native addons, you will need to add: ## Filesystem access -If you need read access to more of the filesystem, or write access to the filesystem, you can enable this: +If you need read access to more of the filesystem, or write access to the +filesystem, you can enable this: ```js "permissions": { @@ -66,14 +76,16 @@ If you need read access to more of the filesystem, or write access to the filesy :::tip -In a future release of Companion, we intend to require the user to grant access to specific paths to each connection. -View this as a request for more access, it may or may not be granted by the user. +In a future release of Companion, we intend to require the user to grant access +to specific paths to each connection. View this as a request for more access, it +may or may not be granted by the user. ::: ## Insecure OpenSSL algorithms -In some rare cases, your module may need to talk to old devices which use now deprecated encryption algorithms. +In some rare cases, your module may need to talk to old devices which use now +deprecated encryption algorithms. ```js "permissions": { @@ -81,4 +93,5 @@ In some rare cases, your module may need to talk to old devices which use now de } ``` -This currently translates to the process being run with the [`--openssl-legacy-provider` argument](https://nodejs.org/api/cli.html#--openssl-legacy-provider). +This currently translates to the process being run with the +[`--openssl-legacy-provider` argument](https://nodejs.org/api/cli.html#--openssl-legacy-provider). diff --git a/for-developers/module-development/connection-advanced/setting-custom-variables.md b/for-developers/module-development/connection-advanced/setting-custom-variables.md index 7b6f206..af67ed2 100644 --- a/for-developers/module-development/connection-advanced/setting-custom-variables.md +++ b/for-developers/module-development/connection-advanced/setting-custom-variables.md @@ -9,15 +9,25 @@ description: How to set custom variables in actions. This is an experimental idea, that may be removed without notice. -Consider instead using [value feedbacks](../connection-basics/feedbacks.md#feedback-types) to allow the user to store a feedback into a local variable. +Consider instead using +[value feedbacks](../connection-basics/feedbacks.md#feedback-types) to allow the +user to store a feedback into a local variable. ::: -Sometimes, an action can produce a bit of data that the user may want to do something with. In these cases, it doesn't make sense to write it to a variable from your module, as another action on the same button could overwrite it too soon. +Sometimes, an action can produce a bit of data that the user may want to do +something with. In these cases, it doesn't make sense to write it to a variable +from your module, as another action on the same button could overwrite it too +soon. -Instead, you can output to a custom-variable. To do so, you can add an input field of type ['custom-variable'](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCustomVariable.html). The options to this are automatically populated for you. +Instead, you can output to a custom-variable. To do so, you can add an input +field of type +['custom-variable'](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCustomVariable.html). +The options to this are automatically populated for you. -Then inside your action callback, you can do a call like `this.setCustomVariableValue(action.options.result, 'Your value')` to set the value. +Then inside your action callback, you can do a call like +`this.setCustomVariableValue(action.options.result, 'Your value')` to set the +value. :::note @@ -27,10 +37,14 @@ If the variable id is not valid you will not be informed. Some additional rules around this: -- Remember that these variables are owned by the user. You should only change them when asked. -- This must be opt-in by the user. The input field will default to 'None', and you must respect that -- You must not set the value of any custom variables at times other than the result of an action -- You must not attempt to discover the custom variables in any way other than the value of this input field. +- Remember that these variables are owned by the user. You should only change + them when asked. +- This must be opt-in by the user. The input field will default to 'None', and + you must respect that +- You must not set the value of any custom variables at times other than the + result of an action +- You must not attempt to discover the custom variables in any way other than + the value of this input field. ## Further Reading diff --git a/for-developers/module-development/connection-basics/actions.md b/for-developers/module-development/connection-basics/actions.md index 7acac79..c8e5a1a 100644 --- a/for-developers/module-development/connection-basics/actions.md +++ b/for-developers/module-development/connection-basics/actions.md @@ -5,23 +5,35 @@ sidebar_position: 16 description: Module action definition details. --- -Actions are the heart of many modules: they define what will happen when a user pushes a button or runs a trigger. +Actions are the heart of many modules: they define what will happen when a user +pushes a button or runs a trigger. -This section explains how to define actions, provide options to the user, and respond when the user invokes the action. +This section explains how to define actions, provide options to the user, and +respond when the user invokes the action. ## API call: `setActionDefinitions()` -Your module defines the list of actions it supports by making a call to [`this.setActionDefinitions({ ...some actions here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setactiondefinitions). You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to update the list of actions exposed. +Your module defines the list of actions it supports by making a call to +[`this.setActionDefinitions({ ...some actions here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setactiondefinitions). +You will need to do this as part of your `init()` method, but can also call it +at any other time if you wish to update the list of actions exposed. :::warning -Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. +Please try not to call this method too often, as updating the list has a cost. +If you are calling it multiple times in a short span of time, consider if it +would be possible to batch the calls so it is only done once. ::: ## Action definitions -The [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) includes a file `src/actions.ts` which is where your actions should be defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the actions definitions into even more files/folders. +The +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) +includes a file `src/actions.ts` which is where your actions should be defined. +It is not required to use this structure, but it keeps it more readable than +having everything in one file. More complex modules will likely want to split +the actions definitions into even more files/folders. All the actions are passed in as a single JavaScript object, in the form of: @@ -47,20 +59,35 @@ The minimum action definition looks like: ### Action execution (callback) -The callback function is called when the action is executed (i.e. associated button is pressed). +The callback function is called when the action is executed (i.e. associated +button is pressed). It is called with 2 parameters: -- `action` - an object containing the options the action was executed with, along with some extra identifiers that can be useful -- `context` - since API 1.1. This contains some useful methods tied to the execution of the action +- `action` - an object containing the options the action was executed with, + along with some extra identifiers that can be useful +- `context` - since API 1.1. This contains some useful methods tied to the + execution of the action -It is safe for your callback to throw an error, Companion will catch and log the error for you. +It is safe for your callback to throw an error, Companion will catch and log the +error for you. #### Synchronous and asynchronous execution -Callback functions may either execute synchronously and return `undefined`, or asynchronously and return a promise that resolves `undefined` (including by directly returning in an `async` function). - -Before Companion 3.5, when a series of actions was executed, each action's callback would be called in sequence, with no delay between actions (unless an action was defined with a relative or absolute delay) and no waiting for asynchronous callback functions' returned promises to resolve or reject. From Companion 3.5 onward, actions may be defined to run **in sequence** (by putting them in an action-group in the Admin interface) -- waiting for the promise returned by an asynchronous callback function to resolve before continuing. If you want your action to support delaying subsequent actions until completed, you must write your callback to not resolve the promise it returns until the action has completed. For example: +Callback functions may either execute synchronously and return `undefined`, or +asynchronously and return a promise that resolves `undefined` (including by +directly returning in an `async` function). + +Before Companion 3.5, when a series of actions was executed, each action's +callback would be called in sequence, with no delay between actions (unless an +action was defined with a relative or absolute delay) and no waiting for +asynchronous callback functions' returned promises to resolve or reject. From +Companion 3.5 onward, actions may be defined to run **in sequence** (by putting +them in an action-group in the Admin interface) -- waiting for the promise +returned by an asynchronous callback function to resolve before continuing. If +you want your action to support delaying subsequent actions until completed, you +must write your callback to not resolve the promise it returns until the action +has completed. For example: ```js const actions = [ @@ -103,33 +130,50 @@ const actions = [ :::note -As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in textinput fields are now automatically parsed. +As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in +textinput fields are now automatically parsed. -As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to parse variables themselves, Companion does it for you based on the fields describing of the options. +As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to +parse variables themselves, Companion does it for you based on the fields +describing of the options. ::: -Between API v1.1 and API v1.14, a `context` object is passed as the second argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. +Between API v1.1 and API v1.14, a `context` object is passed as the second +argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. -The `context` object in these versions includes a special version of the `parseVariablesInString()` method that allows Companion to know what control the parse was being run for. This allowed it to parse local variables. If you use `parseVariablesInString` off the `InstanceBase` class instead, any local variables would not be supported. +The `context` object in these versions includes a special version of the +`parseVariablesInString()` method that allows Companion to know what control the +parse was being run for. This allowed it to parse local variables. If you use +`parseVariablesInString` off the `InstanceBase` class instead, any local +variables would not be supported. ### Additional properties -There are more properties available, which are described in full in [the autogenerated Actions documentation on GitHub](https://bitfocus.github.io/companion-module-base/interfaces/CompanionActionDefinition.html) +There are more properties available, which are described in full in +[the autogenerated Actions documentation on GitHub](https://bitfocus.github.io/companion-module-base/interfaces/CompanionActionDefinition.html) -The `options` property of the action definition is an array of input types, see the [input fields](./input-field-types.md) page for more details. +The `options` property of the action definition is an array of input types, see +the [input fields](./input-field-types.md) page for more details. ### UI Presentation -The Companion UI will sort your actions by name when presenting them in a list. You can add a longer description line of text with the `description` property. +The Companion UI will sort your actions by name when presenting them in a list. +You can add a longer description line of text with the `description` property. -Since [API 2.0](../api-changes/v2.0.md), you can customise the sort order of the actions by setting the `sortName` property on an action definition. When this is set, it will be used instead of the `name` when sorting the action definitions alphabetically. +Since [API 2.0](../api-changes/v2.0.md), you can customise the sort order of the +actions by setting the `sortName` property on an action definition. When this is +set, it will be used instead of the `name` when sorting the action definitions +alphabetically. ### Subscribe & unsubscribe flow -Sometimes it is useful to know what actions and options are being used. This is common for devices which have thousands of properties, or if loading and maintaining a bit of data has a cost, such as requiring polling to fetch. +Sometimes it is useful to know what actions and options are being used. This is +common for devices which have thousands of properties, or if loading and +maintaining a bit of data has a cost, such as requiring polling to fetch. -On the action definition, it is possible to register some additional callbacks to be informed about the actions. +On the action definition, it is possible to register some additional callbacks +to be informed about the actions. ```js const actions = {} @@ -153,21 +197,35 @@ actions['set_source'] = { } ``` -Whenever an action is added to a button, subscribe will be called. -Whenever an action is removed from a button, unsubscribe will be called. -Whenever the options of an action on a button is changed, unsubscribe will be called, followed by subscribe, then the callback. - -It is also possible to force either unsubscribe or subscribe to be called for every action, by calling `this.subscribeActions()` or `this.unsubscribeActions()`. Both functions accept `actionIds` parameters, to only run on a certain action type (eg `this.unsubscribeActions('set_source', 'set_source2')`). -When using these callbacks, it is common to call `this.subscribeActions()` once the connection to the device has been established, to help ensure all the required data gets loaded. - -Since [API v1.13](../api-changes/v1.13.md), it is possible to specify `skipUnsubscribeOnOptionsChange` to avoid excessive unsubscribe calls when options are changed. And `optionsToIgnoreForSubscribe` can be used to limit which fields are able to trigger `subscribe` calls. - -Since [API v2.0](../api-changes/v2.0.md), as Companion is responsible for all variable and expression parsing, `optionsToMonitorForSubscribe` should be used instead when wanting to limit which fields trigger `subscribe` calls. +Whenever an action is added to a button, subscribe will be called. Whenever an +action is removed from a button, unsubscribe will be called. Whenever the +options of an action on a button is changed, unsubscribe will be called, +followed by subscribe, then the callback. + +It is also possible to force either unsubscribe or subscribe to be called for +every action, by calling `this.subscribeActions()` or +`this.unsubscribeActions()`. Both functions accept `actionIds` parameters, to +only run on a certain action type (eg +`this.unsubscribeActions('set_source', 'set_source2')`). When using these +callbacks, it is common to call `this.subscribeActions()` once the connection to +the device has been established, to help ensure all the required data gets +loaded. + +Since [API v1.13](../api-changes/v1.13.md), it is possible to specify +`skipUnsubscribeOnOptionsChange` to avoid excessive unsubscribe calls when +options are changed. And `optionsToIgnoreForSubscribe` can be used to limit +which fields are able to trigger `subscribe` calls. + +Since [API v2.0](../api-changes/v2.0.md), as Companion is responsible for all +variable and expression parsing, `optionsToMonitorForSubscribe` should be used +instead when wanting to limit which fields trigger `subscribe` calls. ### Learn option values -Some actions have many options that users may wish to configure on the device and 'capture' into an action in Companion. -Implementing the [learn option values](../connection-advanced/learn-action-feedback-values.md) flow will allow them to achieve that +Some actions have many options that users may wish to configure on the device +and 'capture' into an action in Companion. Implementing the +[learn option values](../connection-advanced/learn-action-feedback-values.md) +flow will allow them to achieve that ### Result to Custom variable @@ -177,18 +235,23 @@ This is an experimental idea, that may be removed without notice ::: -Some action executions return a value which may want to be used elsewhere in Companion. This could be written [to a custom variable](../connection-advanced/setting-custom-variables.md) +Some action executions return a value which may want to be used elsewhere in +Companion. This could be written +[to a custom variable](../connection-advanced/setting-custom-variables.md) ## TypeScript typings :::tip -This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself +This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any +strong typings had to be managed yourself ::: -As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an `actions` property must be defined. -By default this is `Record>` which means it is loosely typed. +As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an +`actions` property must be defined. By default this is +`Record>` which means it is +loosely typed. To enable strong typings, you can define a type such as: @@ -207,7 +270,8 @@ export interface MyTypes { } ``` -This will tell the InstanceBase that there should be one type of action which is called `route` with an options object as described. +This will tell the InstanceBase that there should be one type of action which is +called `route` with an options object as described. ```ts const act: CompanionActionDefinition = { @@ -238,7 +302,8 @@ const act: CompanionActionDefinition = { :::tip -We can't enforce that the options array matches these types, you will have to do that yourself. +We can't enforce that the options array matches these types, you will have to do +that yourself. ::: diff --git a/for-developers/module-development/connection-basics/connecting.md b/for-developers/module-development/connection-basics/connecting.md index ea8232f..a23c84d 100644 --- a/for-developers/module-development/connection-basics/connecting.md +++ b/for-developers/module-development/connection-basics/connecting.md @@ -5,21 +5,29 @@ sidebar_position: 12 description: Helper classes for connecting to your device. --- -One of the first tasks most modules have to perform is to connect to their device. You can either use an existing connection library from [NPM](https://www.npmjs.com/) if one exists, or you can write your own connection logic inside the module. +One of the first tasks most modules have to perform is to connect to their +device. You can either use an existing connection library from +[NPM](https://www.npmjs.com/) if one exists, or you can write your own +connection logic inside the module. -Companion provides three helper classes to help with writing your connection logic: TCPHelper, UDPHelper, TelnetHelper. These classes provide an asynchronous interface for connecting, communicating and disconnecting from your device. +Companion provides three helper classes to help with writing your connection +logic: TCPHelper, UDPHelper, TelnetHelper. These classes provide an asynchronous +interface for connecting, communicating and disconnecting from your device. -Or if the device uses HTTP, we recommend using the built-in [`fetch` API](https://nodejs.org/en/learn/getting-started/fetch). +Or if the device uses HTTP, we recommend using the built-in +[`fetch` API](https://nodejs.org/en/learn/getting-started/fetch). ## TCPHelper class -The TCPHelper class uses the `EventEmitter` system to provide asynchronous communications. +The TCPHelper class uses the `EventEmitter` system to provide asynchronous +communications. -You start by creating an instance of the class and calling its `connect()` method. -You define the various `on()` callbacks to respond to possible TCP events -- see the example, below. +You start by creating an instance of the class and calling its `connect()` +method. You define the various `on()` callbacks to respond to possible TCP +events -- see the example, below. -Your [action](./actions.md) callbacks will call tcp.send() to send outgoing data. The on('data') callback will receive -and process incoming data. +Your [action](./actions.md) callbacks will call tcp.send() to send outgoing +data. The on('data') callback will receive and process incoming data. The following events are defined in @companion-module/base: @@ -32,7 +40,8 @@ The following events are defined in @companion-module/base: status_change: [status: TCPStatuses, message: string]; ``` -The `TCPHelper` code could all go in the module's `init()` function, for example: +The `TCPHelper` code could all go in the module's `init()` function, for +example: ```typescript class MyModule extends InstanceBase { @@ -78,8 +87,9 @@ class MyModule extends InstanceBase { :::note -In general, broken TCP connections are not detectable through the event system. If you must ensure that the -connection is live, you may need to write a keep-alive responder that periodically sends a query to your device. +In general, broken TCP connections are not detectable through the event system. +If you must ensure that the connection is live, you may need to write a +keep-alive responder that periodically sends a query to your device. ::: @@ -108,9 +118,11 @@ TelnetHelper is very similar to TCPHelper, with these events ## UDPHelper class -UDPHelper is similar to the previous two, but since UDP doesn't maintain connections, you don't have a -`connect()` method. Conversely, there are more options when creating the UDPHelper instance, see the auto-generated documentation -for [UDPHelper options](https://bitfocus.github.io/companion-module-base/interfaces/UDPHelperOptions.html). +UDPHelper is similar to the previous two, but since UDP doesn't maintain +connections, you don't have a `connect()` method. Conversely, there are more +options when creating the UDPHelper instance, see the auto-generated +documentation for +[UDPHelper options](https://bitfocus.github.io/companion-module-base/interfaces/UDPHelperOptions.html). ```ts interface UDPHelperOptions { diff --git a/for-developers/module-development/connection-basics/feedbacks.md b/for-developers/module-development/connection-basics/feedbacks.md index 766cf3c..363297c 100644 --- a/for-developers/module-development/connection-basics/feedbacks.md +++ b/for-developers/module-development/connection-basics/feedbacks.md @@ -5,17 +5,24 @@ sidebar_position: 17 description: Module feedback definition details. --- -Feedbacks allow Companion to reflect device state, using that state for button styles, setting variables, or triggering other behaviour. +Feedbacks allow Companion to reflect device state, using that state for button +styles, setting variables, or triggering other behaviour. -This section explains how to define feedbacks, provide options to the user, and implement the behaviour of the feedback. +This section explains how to define feedbacks, provide options to the user, and +implement the behaviour of the feedback. ## API call: `setFeedbackDefinitions()` -Your module defines the list of feedbacks it supports by making a call to [`this.setFeedbackDefinitions({ ...some feedbacks here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setfeedbackdefinitions). You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to update the list of feedbacks exposed. +Your module defines the list of feedbacks it supports by making a call to +[`this.setFeedbackDefinitions({ ...some feedbacks here... })`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#setfeedbackdefinitions). +You will need to do this as part of your `init()` method, but can also call it +at any other time if you wish to update the list of feedbacks exposed. :::warning -Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. +Please try not to call this method too often, as updating the list has a cost. +If you are calling it multiple times in a short span of time, consider if it +would be possible to batch the calls so it is only done once. ::: @@ -23,33 +30,46 @@ Please try not to call this method too often, as updating the list has a cost. I :::note -Starting with [API 2.0](../api-changes/v2.0.md), it is no longer possible to call `checkFeedbacks()` without any arguments. When you need to call this, you should instead use `checkAllFeedbacks()` +Starting with [API 2.0](../api-changes/v2.0.md), it is no longer possible to +call `checkFeedbacks()` without any arguments. When you need to call this, you +should instead use `checkAllFeedbacks()` ::: -You should tell Companion to re-run the callback of your feedbacks whenever the result is expected to change by calling `this.checkFeedbacks('your-feedback-id', 'another-feedback')`. +You should tell Companion to re-run the callback of your feedbacks whenever the +result is expected to change by calling +`this.checkFeedbacks('your-feedback-id', 'another-feedback')`. :::tip -For modules with many options on feedbacks, you may want to make use of the [subscription flow](#subscribe--unsubscribe-flow) and `this.checkFeedbacksById('abc', 'def')`, to trigger smaller and more controlled invalidations. +For modules with many options on feedbacks, you may want to make use of the +[subscription flow](#subscribe--unsubscribe-flow) and +`this.checkFeedbacksById('abc', 'def')`, to trigger smaller and more controlled +invalidations. ::: ## Feedback types -Companion currently supports three types of [Feedback definitions](https://bitfocus.github.io/companion-module-base/interfaces/CompanionFeedbackDefinitionBase.html): +Companion currently supports three types of +[Feedback definitions](https://bitfocus.github.io/companion-module-base/interfaces/CompanionFeedbackDefinitionBase.html): ### Boolean feedbacks -This is the recommended feedback type, in which the callback returns a simple `true` or `false` value. +This is the recommended feedback type, in which the callback returns a simple +`true` or `false` value. -Inside Companion, users can use these in triggers, as part of feedback logic and to apply style changes of their choice to buttons. +Inside Companion, users can use these in triggers, as part of feedback logic and +to apply style changes of their choice to buttons. ### Value feedbacks -This is a newer addition since [API 1.13](../api-changes/v1.13.md) (Companion 4.1). +This is a newer addition since [API 1.13](../api-changes/v1.13.md) (Companion +4.1). -The user can use this feedback to store a value into a local variable. This allows you to define subscription style lazy loading of values that the user wants to use. +The user can use this feedback to store a value into a local variable. This +allows you to define subscription style lazy loading of values that the user +wants to use. These can return any JSON object, array, or primitive value. @@ -57,21 +77,33 @@ These can return any JSON object, array, or primitive value. These are no longer recommended in most cases. -This type of feedback returns a portion of button style properties that override the user defined style of the button. +This type of feedback returns a portion of button style properties that override +the user defined style of the button. -Commonly, you will have some options on the feedback to let the user choose the background and text colour values to return when true. However this is often too rigid and does not give the user the customisation abilities they desire. +Commonly, you will have some options on the feedback to let the user choose the +background and text colour values to return when true. However this is often too +rigid and does not give the user the customisation abilities they desire. -They can also be used to return image pixel buffers, to show some custom content, although this is no longer recommended +They can also be used to return image pixel buffers, to show some custom +content, although this is no longer recommended :::tip -In older versions of Companion, these were the only available type of feedback. We recommend that older modules should [update their feedbacks to boolean feedbacks](../connection-advanced/migrating-legacy-to-boolean-feedbacks.md) whenever possible. +In older versions of Companion, these were the only available type of feedback. +We recommend that older modules should +[update their feedbacks to boolean feedbacks](../connection-advanced/migrating-legacy-to-boolean-feedbacks.md) +whenever possible. ::: ## Feedback definitions -The [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) includes a file `src/feedbacks.ts` which is where your feedbacks should be defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the feedback definitions into even more files/folders. +The +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) +includes a file `src/feedbacks.ts` which is where your feedbacks should be +defined. It is not required to use this structure, but it keeps it more readable +than having everything in one file. More complex modules will likely want to +split the feedback definitions into even more files/folders. All the feedbacks are passed in a single JavaScript object, like @@ -111,44 +143,62 @@ The minimum boolean feedback definition is as follows: ### Feedback execution (callback) -The callback function is called when the feedback is executed, either shortly after the module calls `this.checkFeedbacks()`, or after the feedback options are changed. +The callback function is called when the feedback is executed, either shortly +after the module calls `this.checkFeedbacks()`, or after the feedback options +are changed. It is called with 2 parameters: -- `feedback` - an object containing the options the feedback is executed with, along with some extra identifiers that can be useful -- `context` - since API 1.1. This contains some useful methods tied to the execution of the feedback +- `feedback` - an object containing the options the feedback is executed with, + along with some extra identifiers that can be useful +- `context` - since API 1.1. This contains some useful methods tied to the + execution of the feedback -It is safe for your callback to throw an error, Companion will catch and log the error for you and treat the feedback result as falsey. +It is safe for your callback to throw an error, Companion will catch and log the +error for you and treat the feedback result as falsey. -The expected values you can return from this depend on the [type of the feedback](#feedback-types). +The expected values you can return from this depend on the +[type of the feedback](#feedback-types). #### Synchronous and asynchronous execution -Starting with API v1.1, feedback callbacks can be async or return a promise if you need. +Starting with API v1.1, feedback callbacks can be async or return a promise if +you need. -You should not be performing any network requests here, but it can be necessary when generating images or using other native code. +You should not be performing any network requests here, but it can be necessary +when generating images or using other native code. :::tip -You must make sure to use a sensible timeout on any async execution, or your feedback can get stuck showing a stale value. +You must make sure to use a sensible timeout on any async execution, or your +feedback can get stuck showing a stale value. ::: #### Using variables -Since API v1.1, it has been possible to use variables in feedback callbacks. This makes your feedbacks much more powerful as it lets the user build more complex interactions and systems. +Since API v1.1, it has been possible to use variables in feedback callbacks. +This makes your feedbacks much more powerful as it lets the user build more +complex interactions and systems. :::note -As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in textinput fields are now automatically parsed. +As of [API v1.13](../api-changes/v1.13.md) (Companion 4.1), variables in +textinput fields are now automatically parsed. -As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to parse variables themselves, Companion does it for you based on the fields describing of the options. +As of [API v2.0](../api-changes/v2.0.md) (Companion 4.3), modules are unable to +parse variables themselves, Companion does it for you based on the fields +describing of the options. ::: -Between API v1.1 and API v1.14, a `context` object is passed as the second argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. +Between API v1.1 and API v1.14, a `context` object is passed as the second +argument in the `callback`, `subscribe`, `unsubscribe` and `learn` callbacks. -The `context` object in these versions includes a special version of the `parseVariablesInString()` method that allows Companion to track which variables are referenced by each feedback, so that they can be re-executed whenever the parsed variables changed. +The `context` object in these versions includes a special version of the +`parseVariablesInString()` method that allows Companion to track which variables +are referenced by each feedback, so that they can be re-executed whenever the +parsed variables changed. ```js { @@ -175,12 +225,22 @@ The `context` object in these versions includes a special version of the `parseV #### Inverting boolean feedbacks -Since [API v1.5](../api-changes/v1.5.md) (Companion 3.1), Companion provides built-in support for 'inverting' the value of boolean feedbacks. This is done automatically for any boolean feedbacks your module exposes. +Since [API v1.5](../api-changes/v1.5.md) (Companion 3.1), Companion provides +built-in support for 'inverting' the value of boolean feedbacks. This is done +automatically for any boolean feedbacks your module exposes. -If you wish to influence the auto-detection behaviour, you can do so by setting `showInvert: false` on a feedback. If this is an existing feedback, make sure to update any existing usages in an [upgrade scripts](./upgrade-scripts.md), to preserve existing behaviour for users. +If you wish to influence the auto-detection behaviour, you can do so by setting +`showInvert: false` on a feedback. If this is an existing feedback, make sure to +update any existing usages in an [upgrade scripts](./upgrade-scripts.md), to +preserve existing behaviour for users. -If your feedback already provides a field to match a true or false state, we strongly advise removing it and replacing existing usage with the built-in invert property. -A helper function (`CreateUseBuiltinInvertForFeedbacksUpgradeScript`) is provided to generate an upgrade script for your module to convert an existing invert checkbox to the built-in system. It expects a parameter describe the feedbacks to process, and the name of the invert checkbox being replaced: +If your feedback already provides a field to match a true or false state, we +strongly advise removing it and replacing existing usage with the built-in +invert property. A helper function +(`CreateUseBuiltinInvertForFeedbacksUpgradeScript`) is provided to generate an +upgrade script for your module to convert an existing invert checkbox to the +built-in system. It expects a parameter describe the feedbacks to process, and +the name of the invert checkbox being replaced: ```js CreateUseBuiltinInvertForFeedbacksUpgradeScript({ @@ -191,27 +251,41 @@ CreateUseBuiltinInvertForFeedbacksUpgradeScript({ ### Additional properties -There are more properties available, which are described in full in [the autogenerated Feedbacks documentation on GitHub](https://bitfocus.github.io/companion-module-base/interfaces/CompanionFeedbackDefinition.html) +There are more properties available, which are described in full in +[the autogenerated Feedbacks documentation on GitHub](https://bitfocus.github.io/companion-module-base/interfaces/CompanionFeedbackDefinition.html) -The `options` property of the feedback definition is an array of input types, see the [input fields](./input-field-types.md) page for more details. +The `options` property of the feedback definition is an array of input types, +see the [input fields](./input-field-types.md) page for more details. -For boolean feedbacks a `defaultStyle` should be defined. This will give the feedback some default style overrides when the user adds the feedback to a button +For boolean feedbacks a `defaultStyle` should be defined. This will give the +feedback some default style overrides when the user adds the feedback to a +button ### UI Presentation -The Companion UI will sort your feedbacks by name when presenting them in a list. You can add a longer description line of text with the `description` property. +The Companion UI will sort your feedbacks by name when presenting them in a +list. You can add a longer description line of text with the `description` +property. -Since [API 2.0](../api-changes/v2.0.md), you can customise the sort order of the feedbacks by setting the `sortName` property on a feedback definition. When this is set, it will be used instead of the `name` when sorting the feedback definitions alphabetically. +Since [API 2.0](../api-changes/v2.0.md), you can customise the sort order of the +feedbacks by setting the `sortName` property on a feedback definition. When this +is set, it will be used instead of the `name` when sorting the feedback +definitions alphabetically. ### Subscribe & unsubscribe flow -Sometimes you will want to only load state from the device when it is needed by a feedback. This is common for devices which have thousands of properties, or if loading and maintaining a bit of data has a cost, such as requiring polling to fetch. +Sometimes you will want to only load state from the device when it is needed by +a feedback. This is common for devices which have thousands of properties, or if +loading and maintaining a bit of data has a cost, such as requiring polling to +fetch. -This flow changed in [API 2.0](../api-changes/v2.0.md), any existing feedbacks will need migrating to the new flow. +This flow changed in [API 2.0](../api-changes/v2.0.md), any existing feedbacks +will need migrating to the new flow. #### Since API 2.0 -On the feedback definition, it is possible to register an additional callbacks to be informed about the feedbacks. +On the feedback definition, it is possible to register an additional callbacks +to be informed about the feedbacks. ```js const feedbacks = {} @@ -232,27 +306,41 @@ feedbacks['check_source'] = { } ``` -Whenever a feedback is added to a button, the callback will be called. -Whenever a feedback is removed from a button, unsubscribe will be called. -Whenever the options of an feedback on a button is changed, only the callback will be called +Whenever a feedback is added to a button, the callback will be called. Whenever +a feedback is removed from a button, unsubscribe will be called. Whenever the +options of an feedback on a button is changed, only the callback will be called -With this, if you need to do any data loading, you should dispatch but not await this inside the callback, and trigger a reevaluation of the feedback (using either `this.checkFeedbacks()` or `this.checkFeedbacksById()`). +With this, if you need to do any data loading, you should dispatch but not await +this inside the callback, and trigger a reevaluation of the feedback (using +either `this.checkFeedbacks()` or `this.checkFeedbacksById()`). :::tip -To help you decide if you need to perform any data loading, in each call to the `callback` you can now access the options provided to the previous call with `feedback.previousOptions`. -With this you can check whether the options affecting the data loading have changed, and skip the loading process when it is not needed. +To help you decide if you need to perform any data loading, in each call to the +`callback` you can now access the options provided to the previous call with +`feedback.previousOptions`. With this you can check whether the options +affecting the data loading have changed, and skip the loading process when it is +not needed. ::: -It is also possible to force the callbacks for all your feedbacks to be re-executed, by calling `this.checkFeedbacks()` or `this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, to only run on a certain feedback type (eg `this.unsubscribeFeedbacks('set_source', 'set_source2')`). -It is common to call `this.checkFeedbacks()` once the connection to the device has been established, to help ensure all the required data gets loaded. +It is also possible to force the callbacks for all your feedbacks to be +re-executed, by calling `this.checkFeedbacks()` or +`this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, +to only run on a certain feedback type (eg +`this.unsubscribeFeedbacks('set_source', 'set_source2')`). It is common to call +`this.checkFeedbacks()` once the connection to the device has been established, +to help ensure all the required data gets loaded. -Often, you will want to track the specific id of feedbacks which are relying on specific data subscriptions from your device, which can then be used with `this.checkFeedbacksById()` to allow rechecking a very targeted group of feedbacks +Often, you will want to track the specific id of feedbacks which are relying on +specific data subscriptions from your device, which can then be used with +`this.checkFeedbacksById()` to allow rechecking a very targeted group of +feedbacks #### In API 1.15 and earlier -On the feedback definition, it is possible to register some additional callbacks to be informed about the feedbacks. +On the feedback definition, it is possible to register some additional callbacks +to be informed about the feedbacks. ```js const feedbacks = {} @@ -276,36 +364,52 @@ feedbacks['check_source'] = { } ``` -Whenever a feedback is added to a button, subscribe will be called. -Whenever a feedback is removed from a button, unsubscribe will be called. -Whenever the options of an feedback on a button is changed, unsubscribe will be called, followed by subscribe, then the callback. +Whenever a feedback is added to a button, subscribe will be called. Whenever a +feedback is removed from a button, unsubscribe will be called. Whenever the +options of an feedback on a button is changed, unsubscribe will be called, +followed by subscribe, then the callback. -If the referenced variables change, the callback will be called without any calls to unsubscribe or subscribe. +If the referenced variables change, the callback will be called without any +calls to unsubscribe or subscribe. :::warning -There was a behaviour change in [API 1.13](../api-changes/v1.13.md). With all variables now being parsed by Companion when building the `options`, it no longer made sense to call unsubscribe and subscribe on every options change, so they will only be called when adding or removing the feedback +There was a behaviour change in [API 1.13](../api-changes/v1.13.md). With all +variables now being parsed by Companion when building the `options`, it no +longer made sense to call unsubscribe and subscribe on every options change, so +they will only be called when adding or removing the feedback ::: -It is also possible to force either unsubscribe or subscribe to be called for every feedback, by calling `this.subscribeFeedbacks()` or `this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, to only run on a certain feedback type (eg `this.unsubscribeFeedbacks('set_source', 'set_source2')`). -When using these callbacks, it is common to call `this.subscribeFeedbacks()` once the connection to the device has been established, to help ensure all the required data gets loaded. +It is also possible to force either unsubscribe or subscribe to be called for +every feedback, by calling `this.subscribeFeedbacks()` or +`this.unsubscribeFeedbacks()`. Both functions accept `feedbackIds` parameters, +to only run on a certain feedback type (eg +`this.unsubscribeFeedbacks('set_source', 'set_source2')`). When using these +callbacks, it is common to call `this.subscribeFeedbacks()` once the connection +to the device has been established, to help ensure all the required data gets +loaded. ### Learn option values -Some feedbacks have many options that users may wish to configure on the device and 'capture' into a feedback in Companion. -Implementing the [learn option values](../connection-advanced/learn-action-feedback-values.md) flow will allow them to achieve that +Some feedbacks have many options that users may wish to configure on the device +and 'capture' into a feedback in Companion. Implementing the +[learn option values](../connection-advanced/learn-action-feedback-values.md) +flow will allow them to achieve that ## TypeScript typings :::tip -This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself +This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any +strong typings had to be managed yourself ::: -As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an `feedbacks` property must be defined. -By default this is `Record>` which means it is loosely typed. +As part of the `InstanceTypes` generic argument passed to `InstanceBase`, an +`feedbacks` property must be defined. By default this is +`Record>` which means it +is loosely typed. To enable strong typings, you can define a type such as: @@ -325,7 +429,8 @@ export interface MyTypes { } ``` -This will tell the InstanceBase that there should be one type of feedback which is called `route` with an options object as described. +This will tell the InstanceBase that there should be one type of feedback which +is called `route` with an options object as described. ```ts const act: CompanionFeedbackDefinition = { @@ -356,7 +461,8 @@ const act: CompanionFeedbackDefinition = { :::tip -We can't enforce that the options array matches these types, you will have to do that yourself. +We can't enforce that the options array matches these types, you will have to do +that yourself. ::: diff --git a/for-developers/module-development/connection-basics/index.md b/for-developers/module-development/connection-basics/index.md index 109e379..1716c7a 100644 --- a/for-developers/module-development/connection-basics/index.md +++ b/for-developers/module-development/connection-basics/index.md @@ -4,4 +4,5 @@ description: Basic API calls and objects for Companion connection modules auto_toc: 2 --- -This section describes the basic elements of the Companion connection-module API. +This section describes the basic elements of the Companion connection-module +API. diff --git a/for-developers/module-development/connection-basics/input-field-types.md b/for-developers/module-development/connection-basics/input-field-types.md index 98cd074..e322550 100644 --- a/for-developers/module-development/connection-basics/input-field-types.md +++ b/for-developers/module-development/connection-basics/input-field-types.md @@ -5,12 +5,16 @@ sidebar_position: 18 description: Module input field types and definition details. --- -Companion has a standardised set of input fields usable across [action](./actions.md), [feedback](./feedbacks.md), or [user-config](./user-configuration.md) definitions. -There are some small differences in what is available where, documented here. +Companion has a standardised set of input fields usable across +[action](./actions.md), [feedback](./feedbacks.md), or +[user-config](./user-configuration.md) definitions. There are some small +differences in what is available where, documented here. ## Option types -When defining actions, feedbacks and module config definitions, the object includes a property called `options:` that takes a list of input-field definitions. For example, +When defining actions, feedbacks and module config definitions, the object +includes a property called `options:` that takes a list of input-field +definitions. For example, ```javascript { @@ -43,30 +47,55 @@ When defining actions, feedbacks and module config definitions, the object inclu } ``` -All the types are described in the auto-generated [api documentation](https://bitfocus.github.io/companion-module-base/), linked below. Unfortunately it is only possible to view the documentation for the latest version of `@companion-module/base`, but we do our best to clarify when things were added inside the documentation. +All the types are described in the auto-generated +[api documentation](https://bitfocus.github.io/companion-module-base/), linked +below. Unfortunately it is only possible to view the documentation for the +latest version of `@companion-module/base`, but we do our best to clarify when +things were added inside the documentation. -There are some [common properties](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBase.html) across every type of input. Each type can also take additional properties as documented: +There are some +[common properties](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBase.html) +across every type of input. Each type can also take additional properties as +documented: -- [Static Text](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldStaticText.html) `type: 'static-text'` -- [Text](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldTextInput.html) `type: 'textinput'` -- [Color Picker](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldColor.html) `type: 'colorpicker'` -- [Dropdown](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldDropdown.html) `type: 'dropdown'` -- [Multi Dropdown](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldMultiDropdown.html) `type: 'multidropdown'` -- [Checkbox](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCheckbox.html) `type: 'checkbox'` -- [Number](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldNumber.html) `type: 'number'` +- [Static Text](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldStaticText.html) + `type: 'static-text'` +- [Text](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldTextInput.html) + `type: 'textinput'` +- [Color Picker](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldColor.html) + `type: 'colorpicker'` +- [Dropdown](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldDropdown.html) + `type: 'dropdown'` +- [Multi Dropdown](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldMultiDropdown.html) + `type: 'multidropdown'` +- [Checkbox](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCheckbox.html) + `type: 'checkbox'` +- [Number](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldNumber.html) + `type: 'number'` Actions also accept: -- [Custom Variable](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCustomVariable.html) `type: 'custom-variable'` +- [Custom Variable](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldCustomVariable.html) + `type: 'custom-variable'` User-Config options also accept: -- [Bonjour Device](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBonjourDevice.html) `type: 'bonjour-device'` -- [Input Field Secret](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldSecret.html) `type: 'secret-text'` +- [Bonjour Device](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBonjourDevice.html) + `type: 'bonjour-device'` +- [Input Field Secret](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldSecret.html) + `type: 'secret-text'` ## Further Readings -It is possible that there are some new field types not linked to in the list above. You can discover these in the 'Hierarchy' section of [the `CompanionInputFieldBase` doc page](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBase.html), or for the specific uses: Here's a starting point for [action input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionActionInputField.html), for [feedback input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionFeedbackInputField.html) and for [user-config input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionConfigField.html) +It is possible that there are some new field types not linked to in the list +above. You can discover these in the 'Hierarchy' section of +[the `CompanionInputFieldBase` doc page](https://bitfocus.github.io/companion-module-base/interfaces/CompanionInputFieldBase.html), +or for the specific uses: Here's a starting point for +[action input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionActionInputField.html), +for +[feedback input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionFeedbackInputField.html) +and for +[user-config input fields](https://bitfocus.github.io/companion-module-base/types/SomeCompanionConfigField.html) ### Topics mentioned here: diff --git a/for-developers/module-development/connection-basics/logging.md b/for-developers/module-development/connection-basics/logging.md index 739e477..6908f8b 100644 --- a/for-developers/module-development/connection-basics/logging.md +++ b/for-developers/module-development/connection-basics/logging.md @@ -5,11 +5,14 @@ sidebar_position: 11 description: Logging in your module --- -There are a few different ways to produce logs from your module. Which one to use depends on whether these logs should end up in front of users or are for debugging. +There are a few different ways to produce logs from your module. Which one to +use depends on whether these logs should end up in front of users or are for +debugging. ## InstanceBase methods -This is the most common method for producing logs in modules, as it has been supported since the beginning. +This is the most common method for producing logs in modules, as it has been +supported since the beginning. On your class, you can do one of the following to produce a log line: @@ -22,17 +25,23 @@ this.log('debug', 'Some debug message') ## `console.log` and friends -If you want to produce some debug logging from your module code, you can use the built-in `console` methods such as `console.log` and `console.error`. +If you want to produce some debug logging from your module code, you can use the +built-in `console` methods such as `console.log` and `console.error`. -These are treated as debug logs, and will only be shown inside the module debug log view; accessible from the popout menu in the connections list. +These are treated as debug logs, and will only be shown inside the module debug +log view; accessible from the popout menu in the connections list. ## `createModuleLogger` -This is a new method of logging in the [API 2.0](../api-changes/v2.0.md). You can now produce a full range of log levels without passing around your class instance. +This is a new method of logging in the [API 2.0](../api-changes/v2.0.md). You +can now produce a full range of log levels without passing around your class +instance. -Loggers created this way work from anywhere in your module and route to the same destination as the instance methods. +Loggers created this way work from anywhere in your module and route to the same +destination as the instance methods. -These loggers can be created with an optional prefix, which appears in the log output and helps produce structured logs. +These loggers can be created with an optional prefix, which appears in the log +output and helps produce structured logs. ```ts import { createModuleLogger } from '@companion-module/base' @@ -42,4 +51,5 @@ const logger = createModuleLogger('SomePrefix') logger.error('something happened!') ``` -These logs will make their way into the Companion log, except for the `debug` level which will only be in the module debug log. +These logs will make their way into the Companion log, except for the `debug` +level which will only be in the module debug log. diff --git a/for-developers/module-development/connection-basics/overview.md b/for-developers/module-development/connection-basics/overview.md index a69e249..51ad5df 100644 --- a/for-developers/module-development/connection-basics/overview.md +++ b/for-developers/module-development/connection-basics/overview.md @@ -7,13 +7,22 @@ description: Module method overview. TODO: API 2.0 -The module/Companion API is primarily defined by the generic class `InstanceBase<>`, which is provided by `@companion-module/base`. Your module's code will extend that class to fill out the missing base class's methods as describe here, and you will call many of the ones provided to expose functionality into Companion. +The module/Companion API is primarily defined by the generic class +`InstanceBase<>`, which is provided by `@companion-module/base`. Your module's +code will extend that class to fill out the missing base class's methods as +describe here, and you will call many of the ones provided to expose +functionality into Companion. -The API can be divided into (1) exposing your module class (2) methods that get called by Companion during the life of your module (3) other methods are called by you to tell Companion how to interact with the end-users and (4) various helper classes and functions that are not part of `InstanceBase<>`. +The API can be divided into (1) exposing your module class (2) methods that get +called by Companion during the life of your module (3) other methods are called +by you to tell Companion how to interact with the end-users and (4) various +helper classes and functions that are not part of `InstanceBase<>`. ## Exposing your module class -The main component of this is to export your class, so that Companion can import and execute it. This should be done at the top-level of _src/main.ts_ (if you're using the [recommended file structure](../module-setup/file-structure.md)). +The main component of this is to export your class, so that Companion can import +and execute it. This should be done at the top-level of _src/main.ts_ (if you're +using the [recommended file structure](../module-setup/file-structure.md)). In ESM this typically this like: @@ -37,7 +46,9 @@ module.exports.UpgradeScripts = [...] // If you have any upgrade scripts :::tip -In API 1.x, this was achieved by a call to `runEntrypoint(ModuleInstance, UpgradeScripts)`. This is no longer supported and will need to be updated +In API 1.x, this was achieved by a call to +`runEntrypoint(ModuleInstance, UpgradeScripts)`. This is no longer supported and +will need to be updated ::: @@ -49,13 +60,18 @@ If you are not using TypeScript, you can skip this section :::tip -This has changed in [API 2.0](../api-changes/v2.0.md), before this it was a simpler `TConfig` that was generic for just your module config. +This has changed in [API 2.0](../api-changes/v2.0.md), before this it was a +simpler `TConfig` that was generic for just your module config. ::: -The first step in creating a module is creating the module Instance class. If you are using the recommended [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts), then the module definition is in _src/main.ts_. +The first step in creating a module is creating the module Instance class. If +you are using the recommended +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts), +then the module definition is in _src/main.ts_. -The class has a type parameter which describes many things about your module. If no type is specified, the default is: +The class has a type parameter which describes many things about your module. If +no type is specified, the default is: ```ts export interface InstanceTypes { @@ -67,7 +83,8 @@ export interface InstanceTypes { } ``` -You can override each of these with concrete types, so that TypeScript can offer narrower types throughout your module. +You can override each of these with concrete types, so that TypeScript can offer +narrower types throughout your module. Each page explains the structure and usage of each portion in more detail @@ -75,9 +92,13 @@ Each page explains the structure and usage of each portion in more detail ### `constructor(internal)` -This class constructor is called during instantiation of the class. You should not do much here as Companion is not yet ready to interact with your module. You should only do some small setup tasks, such as creating objects/instances you need and initialising properties on the class. +This class constructor is called during instantiation of the class. You should +not do much here as Companion is not yet ready to interact with your module. You +should only do some small setup tasks, such as creating objects/instances you +need and initialising properties on the class. -Shortly after this `init()` will be called, when Companion is ready to interact with you. +Shortly after this `init()` will be called, when Companion is ready to interact +with you. ### `init(config: TConfig, isFirstInit: boolean, secrets: TSecrets): Promise` @@ -85,61 +106,84 @@ This is called when Companion is ready to properly run your module. The parameters are: -- `config` - the [user-configuration object](./user-configuration.md) as provided by the user -- `isFirstInit` - if this is the first time this instance of your module has been run, this will be true -- `secrets` - [the secrets object](./user-configuration.md) as provided by the user - -In this method you should store the `config` and `secrets` if needed, and perform any tasks to setup any connections, or other logic that your class should be running. If you are connecting over an Ethernet connection, consider setting up the connection using [TCPHelper, TelnetHelper, or UDPHelper](./connecting.md) from `@companion-module/base`. In the callbacks for these classes, you can set the connection status by calling `updateStatus`. See the [Connecting to the device](./connecting.md) page for more details. +- `config` - the [user-configuration object](./user-configuration.md) as + provided by the user +- `isFirstInit` - if this is the first time this instance of your module has + been run, this will be true +- `secrets` - [the secrets object](./user-configuration.md) as provided by the + user + +In this method you should store the `config` and `secrets` if needed, and +perform any tasks to setup any connections, or other logic that your class +should be running. If you are connecting over an Ethernet connection, consider +setting up the connection using +[TCPHelper, TelnetHelper, or UDPHelper](./connecting.md) from +`@companion-module/base`. In the callbacks for these classes, you can set the +connection status by calling `updateStatus`. See the +[Connecting to the device](./connecting.md) page for more details. :::tip -Many modules simply call `await this.configUpdated(config, secrets)` as they need to perform the same steps during `configUpdated` +Many modules simply call `await this.configUpdated(config, secrets)` as they +need to perform the same steps during `configUpdated` ::: :::danger -While you should setup any connections you need to make, you must not wait for the connection to complete here. Otherwise, Companion may restart your module if it thinks that this method 'timed out'. +While you should setup any connections you need to make, you must not wait for +the connection to complete here. Otherwise, Companion may restart your module if +it thinks that this method 'timed out'. -Also, until this method has completed, users will not be able to edit the [user-configuration](./user-configuration.md). +Also, until this method has completed, users will not be able to edit the +[user-configuration](./user-configuration.md). -Waiting in `init()` is a common source of bugs, leaving users with unusable connections. +Waiting in `init()` is a common source of bugs, leaving users with unusable +connections. ::: ### `configUpdated(config: TConfig, secrets: TSecrets): Promise` -This is called whenever the user updates [the user-configuration](./user-configuration.md) of the module. +This is called whenever the user updates +[the user-configuration](./user-configuration.md) of the module. -In this you should often destroy any existing connections, and restart them from the new user-configuration +In this you should often destroy any existing connections, and restart them from +the new user-configuration ### `destroy(): Promise` This is called as part of stopping your module. -In this you should gracefully terminate any connections, cleanup any timers and generally ensure nothing will be leaked. +In this you should gracefully terminate any connections, cleanup any timers and +generally ensure nothing will be leaked. -This is the last method that is called for your module when it is no longer needed. +This is the last method that is called for your module when it is no longer +needed. ### `getConfigFields(): SomeCompanionConfigField[]` -This is called whenever the user goes to edit [the user-configuration](./user-configuration.md). +This is called whenever the user goes to edit +[the user-configuration](./user-configuration.md). -The return object of this method is an array of input-field definitions for both the `TConfig` object and the -`TSecrets` object . Input-fields of the type 'secret-text' are automatically -assigned to the `TSecrets` object; the rest will go into the `TConfig` object. +The return object of this method is an array of input-field definitions for both +the `TConfig` object and the `TSecrets` object . Input-fields of the type +'secret-text' are automatically assigned to the `TSecrets` object; the rest will +go into the `TConfig` object. :::tip -Not every field of your config/secrets object needs to be associated with an input-field. For example, -if you want to store some internal state that persists between sessions, it can be added to the config -object and saved with a call to `saveConfig`. +Not every field of your config/secrets object needs to be associated with an +input-field. For example, if you want to store some internal state that persists +between sessions, it can be added to the config object and saved with a call to +`saveConfig`. ::: ## Methods you call directly -There are many more methods than are described here, as they are relevant to a certain area of module functionality, and are described properly on those pages. +There are many more methods than are described here, as they are relevant to a +certain area of module functionality, and are described properly on those pages. This list describes some common utilities @@ -149,9 +193,12 @@ This will write a message to the Companion log from your module ### `updateStatus(status: InstanceStatus, message?: null | string): void` -Call this to update the connected-status of your module. (Updates the status of your module shown on the Connections page.) +Call this to update the connected-status of your module. (Updates the status of +your module shown on the Connections page.) -Provide one of the defined [`status` values](https://bitfocus.github.io/companion-module-base/enums/InstanceStatus.html) and an optional message which will be shown when hovering over it. +Provide one of the defined +[`status` values](https://bitfocus.github.io/companion-module-base/enums/InstanceStatus.html) +and an optional message which will be shown when hovering over it. ### Action/Feedback/Variable/Preset definitions diff --git a/for-developers/module-development/connection-basics/presets-1.x.md b/for-developers/module-development/connection-basics/presets-1.x.md index 83c9eac..b6c89a0 100644 --- a/for-developers/module-development/connection-basics/presets-1.x.md +++ b/for-developers/module-development/connection-basics/presets-1.x.md @@ -7,34 +7,46 @@ description: Module presets definition details. :::warning -This describes how presets worked **before** the overhaul in the [API 2.0](../api-changes/v2.0.md). -If you are using the newer API, check the [new presets page](./presets.md) +This describes how presets worked **before** the overhaul in the +[API 2.0](../api-changes/v2.0.md). If you are using the newer API, check the +[new presets page](./presets.md) ::: -Presets are a description of ready-made buttons that will be presented to the user in the Presets tab on the Buttons page. -The user can then drag-and-drop the preset onto the button-grid, to build out config quickly without having to code it from scratch. +Presets are a description of ready-made buttons that will be presented to the +user in the Presets tab on the Buttons page. The user can then drag-and-drop the +preset onto the button-grid, to build out config quickly without having to code +it from scratch. ## API call: `setPresetDefinitions()` -In order to add presets to a module, you call `this.setPresetDefinitions(presetsDefinitions)` much like how you define actions and feedbacks. +In order to add presets to a module, you call +`this.setPresetDefinitions(presetsDefinitions)` much like how you define actions +and feedbacks. ## Preset types Companion supports two types of presets -- [Button Presets](https://bitfocus.github.io/companion-module-base/interfaces/CompanionButtonPresetDefinition.html) (`type: "button"`) -- [Text Presets](https://bitfocus.github.io/companion-module-base/interfaces/CompanionTextPresetDefinition.html) (`type: "text"`) +- [Button Presets](https://bitfocus.github.io/companion-module-base/interfaces/CompanionButtonPresetDefinition.html) + (`type: "button"`) +- [Text Presets](https://bitfocus.github.io/companion-module-base/interfaces/CompanionTextPresetDefinition.html) + (`type: "text"`) -For the most part you will be defining button presets. See the linked documentation, above, for text presets. +For the most part you will be defining button presets. See the linked +documentation, above, for text presets. ## Button preset definitions -Presets are placed into categories, which show up as separate groups in the Companion admin UI. Other than that, -the property-names for the button preset definition correspond to the nomenclature on the button definitions. +Presets are placed into categories, which show up as separate groups in the +Companion admin UI. Other than that, the property-names for the button preset +definition correspond to the nomenclature on the button definitions. -The only tricky part is that action-lists are nested inside steps, so you don't explicitly write "step 1", but rather the -steps are determined by positions in the steps array. Inside the element of the array, the press action-list is labeled `down:`; the release action-list is labeled `up:`, see the [Actions section](#actions), below for additional options. +The only tricky part is that action-lists are nested inside steps, so you don't +explicitly write "step 1", but rather the steps are determined by positions in +the steps array. Inside the element of the array, the press action-list is +labeled `down:`; the release action-list is labeled `up:`, see the +[Actions section](#actions), below for additional options. The basic structure looks like: @@ -88,11 +100,15 @@ this.setPresetDefinitions(presets) ### Configuring a preset -In addition to the minimal example shown above there are more properties that can be set. +In addition to the minimal example shown above there are more properties that +can be set. -You can see the full list of values that can be set and their valid values in the `style` object [in the autogenerated documentation](https://bitfocus.github.io/companion-module-base/interfaces/CompanionButtonStyleProps.html) +You can see the full list of values that can be set and their valid values in +the `style` object +[in the autogenerated documentation](https://bitfocus.github.io/companion-module-base/interfaces/CompanionButtonStyleProps.html) -Additionally, there are some behaviour options that can be set in the `options` object: +Additionally, there are some behaviour options that can be set in the `options` +object: ```js { @@ -107,14 +123,27 @@ Additionally, there are some behaviour options that can be set in the `options` ### Actions -The `steps` property is where the magic happens. This describes what the action will do when pressed. This used to be defined with `actions` and `release_actions`, but it has been restructured in 3.0 to give some new functionality. +The `steps` property is where the magic happens. This describes what the action +will do when pressed. This used to be defined with `actions` and +`release_actions`, but it has been restructured in 3.0 to give some new +functionality. -In Companion 2.x it was possible to latch buttons, but now that can be achieved with steps. In the typical case a button will have a single step, which will give the behaviour of a normal button. -You can make a latching button by defining a second step which does something different. By default, each time the button is released it will shift to the next step, this can be disabled by setting `options: { stepAutoProgress: false }` for the preset. This likely isn't very useful right now, due to it not being possible to use internal actions in presets. +In Companion 2.x it was possible to latch buttons, but now that can be achieved +with steps. In the typical case a button will have a single step, which will +give the behaviour of a normal button. You can make a latching button by +defining a second step which does something different. By default, each time the +button is released it will shift to the next step, this can be disabled by +setting `options: { stepAutoProgress: false }` for the preset. This likely isn't +very useful right now, due to it not being possible to use internal actions in +presets. -You can add as many steps as you like, and build a button which runs through a whole cue list by simply pressing it. There are internal actions that a user can use to change the step manually. +You can add as many steps as you like, and build a button which runs through a +whole cue list by simply pressing it. There are internal actions that a user can +use to change the step manually. -Tip: You can build a preset for a rotary encoder by setting `options: { rotaryActions: true }`, and defining `rotate_left` and `rotate_right` actions on each step of your button: +Tip: You can build a preset for a rotary encoder by setting +`options: { rotaryActions: true }`, and defining `rotate_left` and +`rotate_right` actions on each step of your button: ```ts steps: [ @@ -137,7 +166,10 @@ steps: [ ], ``` -To define a duration group with a specific delay, you can set additional values inside a step with the delay in milliseconds as the key. This should contain the same structure as the `up` and `down` lists. See the example below as a reference: +To define a duration group with a specific delay, you can set additional values +inside a step with the delay in milliseconds as the key. This should contain the +same structure as the `up` and `down` lists. See the example below as a +reference: ```ts steps: [ @@ -157,18 +189,21 @@ steps: [ ], ``` -Each action inside of the `steps` property can also have a `delay` property specified (in milliseconds). +Each action inside of the `steps` property can also have a `delay` property +specified (in milliseconds). :::tip -You can "simulate" an `internal:wait` action by adding the property `delay:` (in ms) to any action definition. -This will cause it to execute _after_ the delay, and is converted internally to `internal:wait`. +You can "simulate" an `internal:wait` action by adding the property `delay:` (in +ms) to any action definition. This will cause it to execute _after_ the delay, +and is converted internally to `internal:wait`. ::: ### Feedbacks -The `feedbacks` property allows you to define style changes using feedbacks from your module. +The `feedbacks` property allows you to define style changes using feedbacks from +your module. These look similar to actions, but a little different: @@ -188,11 +223,13 @@ feedbacks: [ ] ``` -The feedbackId should match a feedback you have defined, and the options should contain all of the parameters as you defined as the options. +The feedbackId should match a feedback you have defined, and the options should +contain all of the parameters as you defined as the options. ## Standard Colors -Below are some color profiles for typical action and/or feedback combinations we recommend. +Below are some color profiles for typical action and/or feedback combinations we +recommend. | Color | RGB Value | Text color | Usage | | ------ | --------- | ---------- | ------------------------------------------------------------------------------------ | diff --git a/for-developers/module-development/connection-basics/presets.md b/for-developers/module-development/connection-basics/presets.md index 9561b45..853357f 100644 --- a/for-developers/module-development/connection-basics/presets.md +++ b/for-developers/module-development/connection-basics/presets.md @@ -7,40 +7,54 @@ description: Module presets definition details. :::info -This describes the current state of presets in [API 2.0](../api-changes/v2.0.md). -If your module is using an older API version, you want the [old presets page](./presets-1.x.md). +This describes the current state of presets in +[API 2.0](../api-changes/v2.0.md). If your module is using an older API version, +you want the [old presets page](./presets-1.x.md). ::: -Presets are a description of ready-made buttons that will be presented to the user in the Presets tab on the Buttons page. -The user can then drag-and-drop the preset onto the button-grid, to build out config quickly without having to code it from scratch. +Presets are a description of ready-made buttons that will be presented to the +user in the Presets tab on the Buttons page. The user can then drag-and-drop the +preset onto the button-grid, to build out config quickly without having to code +it from scratch. ## API call: `setPresetDefinitions()` -In order to add presets to a module, you call `this.setPresetDefinitions(presetsStructure, presetsDefinitions)` much like how you define actions and feedbacks. However for presets you define your presets and a structure defining the layout separately. This allows for a lot more flexibility, and to reduce a lot of repetition +In order to add presets to a module, you call +`this.setPresetDefinitions(presetsStructure, presetsDefinitions)` much like how +you define actions and feedbacks. However for presets you define your presets +and a structure defining the layout separately. This allows for a lot more +flexibility, and to reduce a lot of repetition :::tip -Make sure you call this after the `this.setActionDefinitions()` and `this.setFeedbackDefinitions()` calls. -If you do it before, the variable replacement will be incomplete, and you will get errors in the logs about the missing action and feedback definitions. +Make sure you call this after the `this.setActionDefinitions()` and +`this.setFeedbackDefinitions()` calls. If you do it before, the variable +replacement will be incomplete, and you will get errors in the logs about the +missing action and feedback definitions. ::: ## Preset types -Currently there is one type of preset. We have plans to introduce more in a future release. +Currently there is one type of preset. We have plans to introduce more in a +future release. -- [Simple Button Preset](https://bitfocus.github.io/companion-module-base/interfaces/CompanionSimplePresetDefinition.html) (`type: "simple"`) +- [Simple Button Preset](https://bitfocus.github.io/companion-module-base/interfaces/CompanionSimplePresetDefinition.html) + (`type: "simple"`) :::info -In API 1.x, there used to be a 'text' preset type too. That has been replaced with the new [structure](#preset-structure) object. +In API 1.x, there used to be a 'text' preset type too. That has been replaced +with the new [structure](#preset-structure) object. ::: ## Simple button preset definitions -This preset type is referred to the 'simple' preset as it offers a bit less flexibility than the other preset types, but is intended to be easier to write while still covering most use cases. +This preset type is referred to the 'simple' preset as it offers a bit less +flexibility than the other preset types, but is intended to be easier to write +while still covering most use cases. Let's start with a minimal example preset button: @@ -85,12 +99,22 @@ this.setPresetDefinitions(structure, presets) ### Actions -The `steps` property is where the magic happens. This describes what the action will do when pressed. In the typical case a button will have a single step, which will give the behaviour of a normal button. -You can make a latching button by defining a second step which does something different. By default, each time the button is released it will shift to the next step, this can be disabled by setting `options: { stepAutoProgress: false }` for the preset. This likely isn't very useful right now, due to it not being possible to use internal actions in presets. +The `steps` property is where the magic happens. This describes what the action +will do when pressed. In the typical case a button will have a single step, +which will give the behaviour of a normal button. You can make a latching button +by defining a second step which does something different. By default, each time +the button is released it will shift to the next step, this can be disabled by +setting `options: { stepAutoProgress: false }` for the preset. This likely isn't +very useful right now, due to it not being possible to use internal actions in +presets. -You can add as many steps as you like, and build a button which runs through a whole cue list by simply pressing it. There are internal actions that a user can use to change the step manually. +You can add as many steps as you like, and build a button which runs through a +whole cue list by simply pressing it. There are internal actions that a user can +use to change the step manually. -Tip: You can build a preset for a rotary encoder by setting `options: { rotaryActions: true }`, and defining `rotate_left` and `rotate_right` actions on each step of your button: +Tip: You can build a preset for a rotary encoder by setting +`options: { rotaryActions: true }`, and defining `rotate_left` and +`rotate_right` actions on each step of your button: ```ts steps: [ @@ -113,7 +137,10 @@ steps: [ ], ``` -To define a duration group with a specific delay, you can set additional values inside a step with the delay in milliseconds as the key. This should contain the same structure as the `up` and `down` lists. See the example below as a reference: +To define a duration group with a specific delay, you can set additional values +inside a step with the delay in milliseconds as the key. This should contain the +same structure as the `up` and `down` lists. See the example below as a +reference: ```ts steps: [ @@ -133,18 +160,21 @@ steps: [ ], ``` -Each action defined can also have a `delay` property specified (in milliseconds). +Each action defined can also have a `delay` property specified (in +milliseconds). :::tip -You can "simulate" an `internal:wait` action by adding the property `delay:` (in ms) to any action definition. -This will cause it to execute _after_ the delay, and is converted internally to `internal:wait`. +You can "simulate" an `internal:wait` action by adding the property `delay:` (in +ms) to any action definition. This will cause it to execute _after_ the delay, +and is converted internally to `internal:wait`. ::: ### Feedbacks -The `feedbacks` property allows you to define style changes using feedbacks from your module. +The `feedbacks` property allows you to define style changes using feedbacks from +your module. These look similar to actions, but a little different: @@ -164,12 +194,17 @@ feedbacks: [ ] ``` -The feedbackId should match a feedback you have defined, and the options should contain the parameters as you defined as the options. +The feedbackId should match a feedback you have defined, and the options should +contain the parameters as you defined as the options. ### Local Variables -You can also set a `localVariables` property to create some local variables on the button. Currently these are limited to be simple static values, intended to make it easier to use a value across the actions, feedbacks and style without repeating it. -By doing this, it becomes much easier for the user to change it if needed. This also allows for better reusing one preset within the preset structure with [the templating groups](#template-groups). +You can also set a `localVariables` property to create some local variables on +the button. Currently these are limited to be simple static values, intended to +make it easier to use a value across the actions, feedbacks and style without +repeating it. By doing this, it becomes much easier for the user to change it if +needed. This also allows for better reusing one preset within the preset +structure with [the templating groups](#template-groups). An example: @@ -184,7 +219,8 @@ localVariables: [ ], ``` -You can then reference these variables like normal variables elsewhere in your presets: +You can then reference these variables like normal variables elsewhere in your +presets: ```javascript style: { @@ -209,9 +245,12 @@ You can then reference these variables like normal variables elsewhere in your p ### Using Expressions -Since API 2.0, most fields in your actions and feedbacks will support expressions (except for the ones which you set `disableAutoExpressions: true` to opt out of this behaviour). +Since API 2.0, most fields in your actions and feedbacks will support +expressions (except for the ones which you set `disableAutoExpressions: true` to +opt out of this behaviour). -Not only can the user define these expressions, but you can do so in your presets too. +Not only can the user define these expressions, but you can do so in your +presets too. For example: @@ -229,11 +268,13 @@ feedbacks: [ ], ``` -When the action or feedback is executed, the expressions will have been precomputed, with the computed value provided directly to you. +When the action or feedback is executed, the expressions will have been +precomputed, with the computed value provided directly to you. ## Preset Structure -In the API 2.0, we now expect you to provide a separate structure alongside the presets to define how they should be arranged within the UI. +In the API 2.0, we now expect you to provide a separate structure alongside the +presets to define how they should be arranged within the UI. A minimal example of this: @@ -248,11 +289,14 @@ const structure = [ ] ``` -In this example, there is a single section containing just 2 presets. This is a very basic presentation, but matches what most modules were doing before API 2.0. +In this example, there is a single section containing just 2 presets. This is a +very basic presentation, but matches what most modules were doing before API +2.0. ### Simple Groups -You can get a bit more structure to how your presets are displayed by using some groups inside each section: +You can get a bit more structure to how your presets are displayed by using some +groups inside each section: ```javascript const structure = [ @@ -279,26 +323,37 @@ const structure = [ ] ``` -These groups will separate out each list of presets into their own blocks, with headings and an optional description between each of them. +These groups will separate out each list of presets into their own blocks, with +headings and an optional description between each of them. -This allows for much more organisation of presets than before, without creating hundreds of sections/categories. +This allows for much more organisation of presets than before, without creating +hundreds of sections/categories. -However, this is still a pretty manual and repetitive way of defining presets. For many, they could use some [templating](#template-groups) +However, this is still a pretty manual and repetitive way of defining presets. +For many, they could use some [templating](#template-groups) :::tip -If you were using the 'text' preset type previously, these groups will help you create the same effect and are just a bit more formalised. +If you were using the 'text' preset type previously, these groups will help you +create the same effect and are just a bit more formalised. ::: ### Template Groups -In a lot of modules, they have many channels/outputs/inputs or some other resource where presets are identical except for one number varying between them. +In a lot of modules, they have many channels/outputs/inputs or some other +resource where presets are identical except for one number varying between them. -A simple matrix/video router module, will commonly produce a preset for each input+output combination, to quickly route each input to each output. This can often produce 100s or 1000s of presets which are almost identical. -In some cases, this has caused issues due to the size of the data produced being a performance drain and occasionally making the modules crash on lower powered machines +A simple matrix/video router module, will commonly produce a preset for each +input+output combination, to quickly route each input to each output. This can +often produce 100s or 1000s of presets which are almost identical. In some +cases, this has caused issues due to the size of the data produced being a +performance drain and occasionally making the modules crash on lower powered +machines -Instead, groups in the new structure can be defined as 'template' groups. This templating, allows for overriding local variables you defined on the presets with different values. +Instead, groups in the new structure can be defined as 'template' groups. This +templating, allows for overriding local variables you defined on the presets +with different values. An example template group: @@ -379,19 +434,30 @@ presets[`route_output`] = { } ``` -In this way, you can use one `route_output` preset as a template for hundreds of combinations inside the Companion UI, with a much much lower cost. +In this way, you can use one `route_output` preset as a template for hundreds of +combinations inside the Companion UI, with a much much lower cost. -As a bonus, these variables also make it easier for users to adjust which input or output is used later if they need to, without finding the correct preset again. +As a bonus, these variables also make it easier for users to adjust which input +or output is used later if they need to, without finding the correct preset +again. ## TypeScript typings -When using typescript, if you strongly type your [actions](./actions.md#typescript-typings) and [feedbacks](./feedbacks.md#typescript-typings) as explained in their respective pages, then in your presets, the API will expect your presets to also be typed as `CompanionPresetDefinitions`. +When using typescript, if you strongly type your +[actions](./actions.md#typescript-typings) and +[feedbacks](./feedbacks.md#typescript-typings) as explained in their respective +pages, then in your presets, the API will expect your presets to also be typed +as `CompanionPresetDefinitions`. -These types get propagated through to the actions and feedback properties on the presets, ensuring that they are also strongly typed. This will help you ensure that your usage of the actions and feedbacks in your presets match the definitions you have created +These types get propagated through to the actions and feedback properties on the +presets, ensuring that they are also strongly typed. This will help you ensure +that your usage of the actions and feedbacks in your presets match the +definitions you have created ## Standard Colors -Below are some color profiles for typical action and/or feedback combinations we recommend. +Below are some color profiles for typical action and/or feedback combinations we +recommend. | Color | RGB Value | Text color | Usage | | ------ | --------- | ---------- | ------------------------------------------------------------------------------------ | @@ -405,7 +471,10 @@ Below are some color profiles for typical action and/or feedback combinations we It is possible to use almost any unicode character or emoji within button text. -Some common ones are listed below (you can copy and paste the glyph directly into your code), or find more. [emojipedia](https://emojipedia.org/) can help you find one suitable for what you need, but we recommend keeping it simple and letting the user change it themselves. +Some common ones are listed below (you can copy and paste the glyph directly +into your code), or find more. [emojipedia](https://emojipedia.org/) can help +you find one suitable for what you need, but we recommend keeping it simple and +letting the user change it themselves. | Glyph | Hex Code | font size | Usage | | ----- | -------- | --------- | ------------------------- | diff --git a/for-developers/module-development/connection-basics/upgrade-scripts.md b/for-developers/module-development/connection-basics/upgrade-scripts.md index 8ac4ffd..0e28d23 100644 --- a/for-developers/module-development/connection-basics/upgrade-scripts.md +++ b/for-developers/module-development/connection-basics/upgrade-scripts.md @@ -5,16 +5,25 @@ sidebar_position: 25 description: Module upgrade script details. --- -Over time you will add new functionality to your module. Sometimes, this can involve changing how existing actions or feedbacks are implemented. +Over time you will add new functionality to your module. Sometimes, this can +involve changing how existing actions or feedbacks are implemented. -When this happens, existing usages of the action or feedback may become broken. The job of the upgrade script is to fix up the actions and feedbacks that the user has already added to their site to handle the changes. +When this happens, existing usages of the action or feedback may become broken. +The job of the upgrade script is to fix up the actions and feedbacks that the +user has already added to their site to handle the changes. ## Exposing upgrade scripts -The [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) includes a separate file: -`src/upgrades.ts`, which is where your upgrades should be defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the upgrade definitions into even more files/folders. For example: a different file for each major upgrade. +The +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) +includes a separate file: `src/upgrades.ts`, which is where your upgrades should +be defined. It is not required to use this structure, but it keeps it more +readable than having everything in one file. More complex modules will likely +want to split the upgrade definitions into even more files/folders. For example: +a different file for each major upgrade. -The upgrades.ts file can export a single variable that contains an array of scripts, to be described next. +The upgrades.ts file can export a single variable that contains an array of +scripts, to be described next. ```ts // upgrades.ts @@ -26,7 +35,10 @@ export const upgradeScripts = [ ### API 2.x -In your main file of code, typically _src/main.ts_ or _src/main.js_ (if you're using the [recommended file structure](../module-setup/file-structure.md)), you should have either `export default class ...` or `module.exports = class ...` to export the class for your module. +In your main file of code, typically _src/main.ts_ or _src/main.js_ (if you're +using the [recommended file structure](../module-setup/file-structure.md)), you +should have either `export default class ...` or `module.exports = class ...` to +export the class for your module. To expose your upgrade scripts, you should do one of: @@ -43,9 +55,16 @@ Which one you use will depend on exactly how they are defined ### API 1.x -The main entrypoint for modules, as described in the [overview page](./overview.md) is the call `runEntrypoint(ModuleInstance, UpgradeScripts)` that you typically place at the top-level of _src/main.ts_ (if you're using the [recommended file structure](../module-setup/file-structure.md)). When Companion loads the "main" file, this function will pass to Companion your module class and a list of upgrade scripts, as will be described here. +The main entrypoint for modules, as described in the +[overview page](./overview.md) is the call +`runEntrypoint(ModuleInstance, UpgradeScripts)` that you typically place at the +top-level of _src/main.ts_ (if you're using the +[recommended file structure](../module-setup/file-structure.md)). When Companion +loads the "main" file, this function will pass to Companion your module class +and a list of upgrade scripts, as will be described here. -The upgrades.ts file can export a single variable that contains an array of scripts, to be described next. +The upgrades.ts file can export a single variable that contains an array of +scripts, to be described next. ```ts // upgrades.ts @@ -70,21 +89,30 @@ runEntrypoint(MyModuleClass, upgradeScripts) ## Testing an upgrade script -In order to test an upgrade script, we recommend that before you add the upgrade script you build out a page of configuration to test with. +In order to test an upgrade script, we recommend that before you add the upgrade +script you build out a page of configuration to test with. -Then you can reimport that page over and over again, each time will re-run it through the upgrade scripts. +Then you can reimport that page over and over again, each time will re-run it +through the upgrade scripts. -This may leave other pages of buttons broken as they will have been run through the first run of the upgrade script, make sure to backup your config first, or use a disposable configuration that is not important to you +This may leave other pages of buttons broken as they will have been run through +the first run of the upgrade script, make sure to backup your config first, or +use a disposable configuration that is not important to you ## Writing an upgrade script :::tip -Each upgrade script will only get run once for each action and feedback, but it is good practice to write the scripts so that they can be executed multiple times. This will help you when testing your script, or if jumping between versions of companion. +Each upgrade script will only get run once for each action and feedback, but it +is good practice to write the scripts so that they can be executed multiple +times. This will help you when testing your script, or if jumping between +versions of companion. ::: -We recommend defining the functions in a dedicated `upgrades.ts` file, as they should not depend on your main class and this helps avoids files growing too long to be manageable. +We recommend defining the functions in a dedicated `upgrades.ts` file, as they +should not depend on your main class and this helps avoids files growing too +long to be manageable. A simple example of a script is: @@ -118,7 +146,10 @@ const UpgradeScripts = [ :::warning -It is very important to not _remove_ an upgrade script once it has been defined. You can change old upgrade scripts if needed, but if the number of scripts gets reduced, then Companion will skip the next one you add for some users (it counts how many have been run) +It is very important to not _remove_ an upgrade script once it has been defined. +You can change old upgrade scripts if needed, but if the number of scripts gets +reduced, then Companion will skip the next one you add for some users (it counts +how many have been run) ::: @@ -126,7 +157,10 @@ The script gets fed the bits of data you may need to do the upgrades. ### The `context` parameter -Currently this contains a single property `currentConfig`, which describes the current state of the user-config object of the instance. This cannot be mutated, and is intended as a reference. If it needs updating it will be present in the `props` too. +Currently this contains a single property `currentConfig`, which describes the +current state of the user-config object of the instance. This cannot be mutated, +and is intended as a reference. If it needs updating it will be present in the +`props` too. More will be added onto this `context` in the future, when there is a need to. @@ -164,29 +198,43 @@ This looks something like: :::warning -The options objects on these actions and feedbacks look _very_ different from how they do in the callback of your action or feedback. +The options objects on these actions and feedbacks look _very_ different from +how they do in the callback of your action or feedback. ::: ### The return value -In your upgrade script, you are expected to return an object which describes which actions or feedbacks changed and whether the new config object. +In your upgrade script, you are expected to return an object which describes +which actions or feedbacks changed and whether the new config object. -Any values in this can be new or cloned objects, or a mutated in place object from props. +Any values in this can be new or cloned objects, or a mutated in place object +from props. -This allows Companion to determine which have been changed and avoid excessive work for the unchanged ones. +This allows Companion to determine which have been changed and avoid excessive +work for the unchanged ones. ## Handling expressions -As the options for your actions and feedbacks in upgrade scripts are either wrapped plain values or wrapped expressions, some care needs to be taken in your upgrade script to ensure the upgrade is safe and won't break or lose the user defined expression. +As the options for your actions and feedbacks in upgrade scripts are either +wrapped plain values or wrapped expressions, some care needs to be taken in your +upgrade script to ensure the upgrade is safe and won't break or lose the user +defined expression. -We offer a few utility scripts which you can import from `@companion-module/base` to help with common cases. If you have something you think would be useful to add, let us know or open a PR. +We offer a few utility scripts which you can import from +`@companion-module/base` to help with common cases. If you have something you +think would be useful to add, let us know or open a PR. -- `FixupNumericOrVariablesValueToExpressions`: If you have a field which used to be a `textinput` and expected a number or variable containing a number, this will take in the wrapped value and convert it to a new wrapped value (or expression) which can be used for `number` input field +- `FixupNumericOrVariablesValueToExpressions`: If you have a field which used to + be a `textinput` and expected a number or variable containing a number, this + will take in the wrapped value and convert it to a new wrapped value (or + expression) which can be used for `number` input field ## Boolean feedbacks -If you are looking to convert 'advanced' feedbacks to 'boolean' feedbacks, we have [a guide on this process](../connection-advanced/migrating-legacy-to-boolean-feedbacks.md) +If you are looking to convert 'advanced' feedbacks to 'boolean' feedbacks, we +have +[a guide on this process](../connection-advanced/migrating-legacy-to-boolean-feedbacks.md) ## Further Reading diff --git a/for-developers/module-development/connection-basics/user-configuration.md b/for-developers/module-development/connection-basics/user-configuration.md index 8f90703..56faa36 100644 --- a/for-developers/module-development/connection-basics/user-configuration.md +++ b/for-developers/module-development/connection-basics/user-configuration.md @@ -5,53 +5,97 @@ sidebar_position: 15 description: Module user configuration and secrets details. --- -The module configuration is like preferences for the connection. E.g. the IP-address of the device controlled by the instance. The config object itself is a JavaScript object defined by you. In TypeScript, you create a type or interface to define your config object and then use that type in declaring your InstanceBase class, i.e. `class ModuleInstance extends InstanceBase` (see src/main.ts in the [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts)). - -Secrets is a new feature (since [API 1.13 - Companion 4.1](../api-changes/v1.13#secrets)). By defining a field as a secret, Companion will store its values in a separate secrets object. This allows Companion to be more careful in avoiding logging of this object, and allows the user to easily omit these values when exporting their configuration, which is beneficial for sharing with others. - -The fields available for secrets is quite limited, as we expect it to only be useful for API keys, usernames, passwords and similar things. If other field types would be useful, let us know and we can look at adding more. +The module configuration is like preferences for the connection. E.g. the +IP-address of the device controlled by the instance. The config object itself is +a JavaScript object defined by you. In TypeScript, you create a type or +interface to define your config object and then use that type in declaring your +InstanceBase class, i.e. +`class ModuleInstance extends InstanceBase` (see src/main.ts in +the +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts)). + +Secrets is a new feature (since +[API 1.13 - Companion 4.1](../api-changes/v1.13#secrets)). By defining a field +as a secret, Companion will store its values in a separate secrets object. This +allows Companion to be more careful in avoiding logging of this object, and +allows the user to easily omit these values when exporting their configuration, +which is beneficial for sharing with others. + +The fields available for secrets is quite limited, as we expect it to only be +useful for API keys, usernames, passwords and similar things. If other field +types would be useful, let us know and we can look at adding more. ## API calls: `getConfigFields()`, `saveConfig()`, `configUpdated()` -As part of creating a module, you should implement the [`getConfigFields()` method](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#getconfigfields). +As part of creating a module, you should implement the +[`getConfigFields()` method](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#getconfigfields). -Companion will call this when the configuration panel is opened for your module, so that it can present the correct fields to the user. See the next section, below, for details. +Companion will call this when the configuration panel is opened for your module, +so that it can present the correct fields to the user. See the next section, +below, for details. -When your module is initialised, you will be provided a copy of the config in the [`init()`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#init) method, and any time the user changes the configuration, [`configUpdated()`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#configupdated) will be called. +When your module is initialised, you will be provided a copy of the config in +the +[`init()`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#init) +method, and any time the user changes the configuration, +[`configUpdated()`](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#configupdated) +will be called. -If you need to programmatically change the config object, for example to save some persistent state or to allow actions to change the config, call `saveConfig(newconfig)`. (This will not trigger `configUpdated()`.) +If you need to programmatically change the config object, for example to save +some persistent state or to allow actions to change the config, call +`saveConfig(newconfig)`. (This will not trigger `configUpdated()`.) :::tip -The `saveConfig()`, `configUpdated()` and `init()` methods also provide or accept a secrets object when you are defining any secret fields. +The `saveConfig()`, `configUpdated()` and `init()` methods also provide or +accept a secrets object when you are defining any secret fields. ::: ## User-Config definitions -The fields you can use here are similar to the ones for actions and feedbacks, but with more limitations. See the [list of field types](./input-field-types.md) for more details. The linked documentation states any limitations that apply when used for the configuration, or if they are not allowed. +The fields you can use here are similar to the ones for actions and feedbacks, +but with more limitations. See the [list of field types](./input-field-types.md) +for more details. The linked documentation states any limitations that apply +when used for the configuration, or if they are not allowed. -The contents of the config and secrets objects must be JSON safe values, due to how they are stored. Make sure to not try and use a non-json safe object or it either won't be saved, or will throw an error that can crash your module. +The contents of the config and secrets objects must be JSON safe values, due to +how they are stored. Make sure to not try and use a non-json safe object or it +either won't be saved, or will throw an error that can crash your module. ### Layout (deprecated) :::tip -Since API v1.14, we are working to unify the layout of this configuration to match elsewhere in Companion, meaning this value is not respected by default. +Since API v1.14, we are working to unify the layout of this configuration to +match elsewhere in Companion, meaning this value is not respected by default. -At the moment (in Companion v4.2/v4.3) it is possible to opt into the old layout, if you are not ready to ensure this works well for your module, you can opt out by adding in the constructor `this.options.disableNewConfigLayout = true`. This should only be done as a temporary measure, at some point in the future this will not be supported. +At the moment (in Companion v4.2/v4.3) it is possible to opt into the old +layout, if you are not ready to ensure this works well for your module, you can +opt out by adding in the constructor +`this.options.disableNewConfigLayout = true`. This should only be done as a +temporary measure, at some point in the future this will not be supported. -If you do this, let us know what is missing for you to switch. We recognise that there may be functionality you need and want to expand upon what the new layout offers. Reach out on [GitHub](https://github.com/bitfocus/companion/issues) to let us know what you need to be able to migrate. +If you do this, let us know what is missing for you to switch. We recognise that +there may be functionality you need and want to expand upon what the new layout +offers. Reach out on [GitHub](https://github.com/bitfocus/companion/issues) to +let us know what you need to be able to migrate. ::: -Each field is required to have a `width` property. This should be a value 1-12, specifying how many columns the field needs in the UI. +Each field is required to have a `width` property. This should be a value 1-12, +specifying how many columns the field needs in the UI. ### Device discovery -If you are connecting over the network, your device may be discoverable using the Bonjour protocol. See the advanced topic [Bonjour Device Discovery](../connection-advanced/bonjour-device-discovery.md) for further details. +If you are connecting over the network, your device may be discoverable using +the Bonjour protocol. See the advanced topic +[Bonjour Device Discovery](../connection-advanced/bonjour-device-discovery.md) +for further details. -If your device uses a different discovery mechanism, we would like to hear about it so that we can expand this support for more devices. Reach out on [GitHub](https://github.com/bitfocus/companion/issues) +If your device uses a different discovery mechanism, we would like to hear about +it so that we can expand this support for more devices. Reach out on +[GitHub](https://github.com/bitfocus/companion/issues) ## Further reading diff --git a/for-developers/module-development/connection-basics/variables.md b/for-developers/module-development/connection-basics/variables.md index 951d246..f9fdd19 100644 --- a/for-developers/module-development/connection-basics/variables.md +++ b/for-developers/module-development/connection-basics/variables.md @@ -5,25 +5,40 @@ sidebar_position: 19 description: Module variable definition details. --- -Variables are a way for modules to expose values to the user, which can be used as part of the button text, as input to some actions or feedbacks and more. This section explains how to define variables and update their values. +Variables are a way for modules to expose values to the user, which can be used +as part of the button text, as input to some actions or feedbacks and more. This +section explains how to define variables and update their values. -The basic workflow is to define your variables using `setVariableDefinitions()`, then set or update the values using `setVariableValues()`. Both of these methods are defined by the module InstanceBase class. +The basic workflow is to define your variables using `setVariableDefinitions()`, +then set or update the values using `setVariableValues()`. Both of these methods +are defined by the module InstanceBase class. ## API call: `setVariableDefinitions()` -Your module should define the list of variables it exposes by making a call to `this.setVariableDefinitions([ ...some variables here... ])`. You will need to do this as part of your `init()` method, but can also call it at any other time if you wish to change the list of variables exposed. +Your module should define the list of variables it exposes by making a call to +`this.setVariableDefinitions([ ...some variables here... ])`. You will need to +do this as part of your `init()` method, but can also call it at any other time +if you wish to change the list of variables exposed. :::warning -Please try not to call this method too often, as updating the list has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. +Please try not to call this method too often, as updating the list has a cost. +If you are calling it multiple times in a short span of time, consider if it +would be possible to batch the calls so it is only done once. ::: ## Variable definitions -The [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) includes a file `src/variables.ts`, which is where your variables should be defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the variable definitions into even more files/folders. +The +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) +includes a file `src/variables.ts`, which is where your variables should be +defined. It is not required to use this structure, but it keeps it more readable +than having everything in one file. More complex modules will likely want to +split the variable definitions into even more files/folders. -All the variable definitions are passed in as a single JavaScript array, in the form of: +All the variable definitions are passed in as a single JavaScript array, in the +form of: ```js ;[ @@ -41,7 +56,10 @@ VariableId must only use letters [a-zA-Z], numbers, underscore, hyphen. ## API call: `setVariableValues()` -At any point in your module you can call `this.setVariableValues({ ... new values ... })`. You can specify as many or few variables as you wish in this call. Only the variables you specify will be updated. +At any point in your module you can call +`this.setVariableValues({ ... new values ... })`. You can specify as many or few +variables as you wish in this call. Only the variables you specify will be +updated. For example: @@ -54,11 +72,14 @@ this.setVariableValues({ }) ``` -Variables can have values of any type, the user can use expressions to manipulate the values you provide. +Variables can have values of any type, the user can use expressions to +manipulate the values you provide. :::warning -Please try to batch variable updates whenever possible, as updating the values has a cost. If you are calling it multiple times in a short span of time, consider if it would be possible to batch the calls so it is only done once. +Please try to batch variable updates whenever possible, as updating the values +has a cost. If you are calling it multiple times in a short span of time, +consider if it would be possible to batch the calls so it is only done once. ::: @@ -66,12 +87,14 @@ Please try to batch variable updates whenever possible, as updating the values h :::tip -This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any strong typings had to be managed yourself +This was introduced in [API v2.0](../api-changes/v2.0.md), prior to this any +strong typings had to be managed yourself ::: -As part of the `InstanceTypes` generic argument passed to `InstanceBase`, a `variables` property must be defined. -By default this is `CompanionVariableValues` which means it is loosely typed. +As part of the `InstanceTypes` generic argument passed to `InstanceBase`, a +`variables` property must be defined. By default this is +`CompanionVariableValues` which means it is loosely typed. To enable strong typings, you can define a type such as: @@ -86,7 +109,10 @@ export interface MyTypes { } ``` -In your calls to `setVariableDefinitions`, you can then type your definitions as `CompanionVariableDefinition`. And calls to `setVariableValues` will expect to receive a `Partial`, helping you match the types. +In your calls to `setVariableDefinitions`, you can then type your definitions as +`CompanionVariableDefinition`. And calls to `setVariableValues` +will expect to receive a `Partial`, helping you match the +types. ## Further Reading diff --git a/for-developers/module-development/home.md b/for-developers/module-development/home.md index 4e28ac0..5a09c57 100644 --- a/for-developers/module-development/home.md +++ b/for-developers/module-development/home.md @@ -7,57 +7,115 @@ description: Developer environment setup specific to module development. So, you want to develop a module for Companion? Welcome! -Companion uses plug-ins to expand its capabilities, we call these plug-ins "modules". For every device you can control with Companion there is a "module" that manages the connection. This page describes how to set up your computer for developing Companion modules. Subsequent pages will provide details on the contents of the module and its lifecycle. +Companion uses plug-ins to expand its capabilities, we call these plug-ins +"modules". For every device you can control with Companion there is a "module" +that manages the connection. This page describes how to set up your computer for +developing Companion modules. Subsequent pages will provide details on the +contents of the module and its lifecycle. ## Prerequisites -Before you start, make sure you have [Installed the Development Tools](../setting-up-developer-environment.md) and familiarized yourself with [Git Workflows](../git-workflows/git-crashcourse.md). +Before you start, make sure you have +[Installed the Development Tools](../setting-up-developer-environment.md) and +familiarized yourself with [Git Workflows](../git-workflows/git-crashcourse.md). This page discusses additional setup specific to Companion modules. ## Install Companion -You can develop modules against any standard release or beta build of Companion. (To develop modules in a core-Companion development process, see the instruction for [headless development](./local-modules#headless-development)) +You can develop modules against any standard release or beta build of Companion. +(To develop modules in a core-Companion development process, see the instruction +for [headless development](./local-modules#headless-development)) -Download and install a recent version from [the website](https://bitfocus.io/user/downloads) +Download and install a recent version from +[the website](https://bitfocus.io/user/downloads) :::tip -Starting with Companion v4.0, the module release cycle has been decoupled from the Companion release cycle: The timing of module version releases are determined by the module developer independently of the Companion releases. +Starting with Companion v4.0, the module release cycle has been decoupled from +the Companion release cycle: The timing of module version releases are +determined by the module developer independently of the Companion releases. -We therefore recommend developing your module using the current stable version to ensure that users will be able to use your module right away instead of having to wait until the current beta is released. +We therefore recommend developing your module using the current stable version +to ensure that users will be able to use your module right away instead of +having to wait until the current beta is released. ::: ## Set up the Development Folder -- Create a modules development folder somewhere on your computer. You can call it whatever you like. -- Open the companion launcher and click the cog in the top right. In versions prior to v4.1 this will reveal a 'Developer modules path' field. Starting in Companion v4.1 it will open up a settings window in which you can set the path. Set it to the development folder you just created. +- Create a modules development folder somewhere on your computer. You can call + it whatever you like. +- Open the companion launcher and click the cog in the top right. In versions + prior to v4.1 this will reveal a 'Developer modules path' field. Starting in + Companion v4.1 it will open up a settings window in which you can set the + path. Set it to the development folder you just created. -Please see the next page: [Setting up a Dev Folder](./local-modules.md) for full details. +Please see the next page: [Setting up a Dev Folder](./local-modules.md) for full +details. :::tip -Companion will load any modules that are in _subfolders_ of the modules development folder. -However, starting with v4.0, note that **your new dev module will show up in the Connections page** but not in the Modules page, since it is not yet part of the official set of Companion modules. +Companion will load any modules that are in _subfolders_ of the modules +development folder. However, starting with v4.0, note that **your new dev module +will show up in the Connections page** but not in the Modules page, since it is +not yet part of the official set of Companion modules. ::: ## Clone or Copy a module from GitHub -With over 700 published modules, you may find a module already written for you device. You can find the GitHub repository for each module by searching [Bitfocus in GitHub](https://github.com/bitfocus). - -- If you want to **contribute to an existing module**, clone it to your development folder using your [preferred git tool](../git-workflows/installing-git.md). (See [Git Crash Course](../git-workflows/git-crashcourse.md) and [The GitHub Workflow](../git-workflows/github-workflow.md) for important details). -- If you are **writing a new module**, then download and expand the zip file for the [TypeScript template module](https://github.com/bitfocus/companion-module-template-ts/archive/refs/heads/main.zip) into the module development folder (see the next section on naming your module). If you prefer, you can clone the [template repo](https://github.com/bitfocus/companion-module-template-ts), but remember to delete the remote link (`git remote remove origin`) before continuing. We encourage you to use TypeScript for all new modules but acknowledge that it isn't for everyone, so we fully support [Javascript](https://github.com/bitfocus/companion-module-template-js) too! -- Alternatively for a new module, you can start by downloading the zip or cloning a module that controls a device similar to yours -- both options can be found under the green **<> Code ▼** button for that module's GitHub repo. Beware: by using another module as a base, you could inherit some subtle misconfigurations or deviations they have made from our recommendations. As with using the template, if you cloned the repo be sure to remove the remote connection by running `git remote remove origin`, since you will be creating a new module rather than modifying the existing one. +With over 700 published modules, you may find a module already written for you +device. You can find the GitHub repository for each module by searching +[Bitfocus in GitHub](https://github.com/bitfocus). + +- If you want to **contribute to an existing module**, clone it to your + development folder using your + [preferred git tool](../git-workflows/installing-git.md). (See + [Git Crash Course](../git-workflows/git-crashcourse.md) and + [The GitHub Workflow](../git-workflows/github-workflow.md) for important + details). +- If you are **writing a new module**, then download and expand the zip file for + the + [TypeScript template module](https://github.com/bitfocus/companion-module-template-ts/archive/refs/heads/main.zip) + into the module development folder (see the next section on naming your + module). If you prefer, you can clone the + [template repo](https://github.com/bitfocus/companion-module-template-ts), but + remember to delete the remote link (`git remote remove origin`) before + continuing. We encourage you to use TypeScript for all new modules but + acknowledge that it isn't for everyone, so we fully support + [Javascript](https://github.com/bitfocus/companion-module-template-js) too! +- Alternatively for a new module, you can start by downloading the zip or + cloning a module that controls a device similar to yours -- both options can + be found under the green + **<> Code ▼** button for that module's GitHub repo. + Beware: by using another module as a base, you could inherit some subtle + misconfigurations or deviations they have made from our recommendations. As + with using the template, if you cloned the repo be sure to remove the remote + connection by running `git remote remove origin`, since you will be creating a + new module rather than modifying the existing one. ### Additional steps for new modules -1. Rename your module's directory _companion-module-mymanufacturer-myproduct_, replacing _mymanufacturer-myproduct_ with appropriate names. Try to think of what is most appropriate for your device: Are there other similar devices by the manufacturer that use the same protocol that the module could support later on? If so try and name it to more easily allow for that. - -2. In at least _package.json_, _companion/manifest.json_ and _companion/HELP.md_, edit the name and description of the module to match what yours is called. The search feature in your IDE is really helpful to find all of the places the name shows up! See the [Module Configuration section](./module-setup/file-structure.md) and especially the [documentation for the manifest.json file](./module-setup/manifest.json.md) for further details. - -3. Please see [Module Configuration](./module-setup/file-structure.md) and the other pages in that section for more details and more options on starting your own module. +1. Rename your module's directory _companion-module-mymanufacturer-myproduct_, + replacing _mymanufacturer-myproduct_ with appropriate names. Try to think of + what is most appropriate for your device: Are there other similar devices by + the manufacturer that use the same protocol that the module could support + later on? If so try and name it to more easily allow for that. + +2. In at least _package.json_, _companion/manifest.json_ and + _companion/HELP.md_, edit the name and description of the module to match + what yours is called. The search feature in your IDE is really helpful to + find all of the places the name shows up! See the + [Module Configuration section](./module-setup/file-structure.md) and + especially the + [documentation for the manifest.json file](./module-setup/manifest.json.md) + for further details. + +3. Please see [Module Configuration](./module-setup/file-structure.md) and the + other pages in that section for more details and more options on starting + your own module. ## Install the dependencies @@ -71,19 +129,31 @@ This will install any dependencies needed by the module. :::tip -If you are using an IDE such as [VS Code](https://code.visualstudio.com/), make the clone your current project -(i.e., open the repository folder), then open a terminal (shell) inside the IDE to ensure you are running yarn in the correct folder. +If you are using an IDE such as [VS Code](https://code.visualstudio.com/), make +the clone your current project (i.e., open the repository folder), then open a +terminal (shell) inside the IDE to ensure you are running yarn in the correct +folder. ::: ## Start working on your module -You are now ready to start developing your module. Here are our suggested next steps: - -- Familiarize yourself with the [Module Configuration](./module-setup/file-structure.md) to understand the general file structure and configuration options, especially if working on a new module. -- Read [Module development 101](./module-development-101.md) for an overview of the development lifecycle. -- Review the recommended [GitHub Workflow](../git-workflows/github-workflow.md) to learn best practices for new features to your codebase. - -You can develop code while the module is running in Companion: whenever you save a file inside your module development folder, Companion will automatically restart any connections using that module. - -If it does not, or you are having issues getting your module to load in then please reach out on [Slack](https://l.companion.free/q/zYXXxnGyd) and we will be happy to assist you in getting started. +You are now ready to start developing your module. Here are our suggested next +steps: + +- Familiarize yourself with the + [Module Configuration](./module-setup/file-structure.md) to understand the + general file structure and configuration options, especially if working on a + new module. +- Read [Module development 101](./module-development-101.md) for an overview of + the development lifecycle. +- Review the recommended [GitHub Workflow](../git-workflows/github-workflow.md) + to learn best practices for new features to your codebase. + +You can develop code while the module is running in Companion: whenever you save +a file inside your module development folder, Companion will automatically +restart any connections using that module. + +If it does not, or you are having issues getting your module to load in then +please reach out on [Slack](https://l.companion.free/q/zYXXxnGyd) and we will be +happy to assist you in getting started. diff --git a/for-developers/module-development/index.md b/for-developers/module-development/index.md index c53357a..7a7b71b 100644 --- a/for-developers/module-development/index.md +++ b/for-developers/module-development/index.md @@ -4,5 +4,9 @@ description: Outline of the Module Development section. auto_toc: 2 --- -This section describes everything you need to know to develop your own modules for Companion. Below is -an outline of the top-level pages and folders in this section. For pages, the main headings inside each file are listed as bulleted lines. Folders are shown preceded by '> ', and the immediate contents of that folder are shown below it using "└─ " to indicate pages (or subfolders) inside that folder. +This section describes everything you need to know to develop your own modules +for Companion. Below is an outline of the top-level pages and folders in this +section. For pages, the main headings inside each file are listed as bulleted +lines. Folders are shown preceded by '> ', and the immediate contents of that +folder are shown below it using "└─ " to indicate pages (or subfolders) inside +that folder. diff --git a/for-developers/module-development/local-modules.md b/for-developers/module-development/local-modules.md index 0af1040..7f1e7d0 100644 --- a/for-developers/module-development/local-modules.md +++ b/for-developers/module-development/local-modules.md @@ -5,18 +5,23 @@ sidebar_position: 2 description: How to load modules in Companion during module development. --- -Starting with Companion 3.0 you can develop, test and use your own module code without the need for the Core Companion development environment. Here is how you do it. +Starting with Companion 3.0 you can develop, test and use your own module code +without the need for the Core Companion development environment. Here is how you +do it. ## Module folder structure -The structure is setup so that you can load multiple modules at the same time. A module folder is specified as described below. -Inside of this folder should be one or more folders that use the following layouts, with each folder corresponding to a different module. +The structure is setup so that you can load multiple modules at the same time. A +module folder is specified as described below. Inside of this folder should be +one or more folders that use the following layouts, with each folder +corresponding to a different module. -1. A git clone of a module from github - This requires some additional setup, as the module will need to be prepared with a `yarn install`, and for some, a `yarn build`. -2. Packaged output - This is a folder that contains a `companion/manifest.json`, `companion/HELP.md`, `package.json`, `main.js` (or another name), and possibly a few other files. - No extra work is needed for this to be loaded +1. A git clone of a module from github This requires some additional setup, as + the module will need to be prepared with a `yarn install`, and for some, a + `yarn build`. +2. Packaged output This is a folder that contains a `companion/manifest.json`, + `companion/HELP.md`, `package.json`, `main.js` (or another name), and + possibly a few other files. No extra work is needed for this to be loaded ## Set up a developer folder @@ -26,39 +31,60 @@ Inside of this folder should be one or more folders that use the following layou ![image](images/launcher.png) -- In the top right corner you will see a Cog. Click on it to show the **Advanced Settings** window: +- In the top right corner you will see a Cog. Click on it to show the **Advanced + Settings** window: ![image](images/launcher-advanced.png) -- In the **Developer** section click on _**Select**_ to specify the directory where you have stored your developer modules. -- Make sure **Enable Developer Modules** is switched on. You can now close the window -- Click on "Launch GUI" to open the Admin interface. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, be sure to choose the "dev" version in the configuration. - If you don't see the developers module, please check the log and switch on debug, maybe the module has crashed. -- You can replace a developers module or files within it while Companion is running. Companion will detect the change and restart only that module without affecting other modules. You can also force a module to reload by disabling and re-enabling a connection. +- In the **Developer** section click on _**Select**_ to specify the directory + where you have stored your developer modules. +- Make sure **Enable Developer Modules** is switched on. You can now close the + window +- Click on "Launch GUI" to open the Admin interface. In the connections list you + should find the connection provided by the developer module. If the developer + module is using the same internal ID as a module that is distributed with + Companion, be sure to choose the "dev" version in the configuration. If you + don't see the developers module, please check the log and switch on debug, + maybe the module has crashed. +- You can replace a developers module or files within it while Companion is + running. Companion will detect the change and restart only that module without + affecting other modules. You can also force a module to reload by disabling + and re-enabling a connection. :::note -The development folder is the one that contains all your module folders, not a module folder itself! +The development folder is the one that contains all your module folders, not a +module folder itself! -For example, if your module repo is in a folder called _module1_ and it's in a folder called _mydev_, i.e. -_mydev/module1_, -the **Developer Module Path** is _**mydev**_ and not _mydev/module1_. +For example, if your module repo is in a folder called _module1_ and it's in a +folder called _mydev_, i.e. _mydev/module1_, the **Developer Module Path** is +_**mydev**_ and not _mydev/module1_. ::: ## RaspberryPI / Headless Linux -- Find the developers module folder on your installation. This is often `/opt/companion-module-dev/`. +- Find the developers module folder on your installation. This is often + `/opt/companion-module-dev/`. - Check the section above on how to structure this folder - Run Companion. -- Open the Admin interface in your Browser. In the connections list you should find the connection provided by the developer module. If the developer module is using the same internal ID as a module that is distributed with Companion, it will override the distributed version. - If you don't see the developers module, please check the log and switch on debug, maybe the module has crashed. +- Open the Admin interface in your Browser. In the connections list you should + find the connection provided by the developer module. If the developer module + is using the same internal ID as a module that is distributed with Companion, + it will override the distributed version. If you don't see the developers + module, please check the log and switch on debug, maybe the module has + crashed. ## Headless development -- If you are running Companion from source in development mode, there is a folder `module-local-dev` inside the repository that gets read for your modules. It follows the same rules for structuring as above. -- You can also use the command-line argument `--extra-module-path` to specify the dev folder. -- Alternatively, you can set the environment variable `COMPANION_DEV_MODULES` to the dev folder. For your convenience, you can put the following in `.env` in your companion source folder: +- If you are running Companion from source in development mode, there is a + folder `module-local-dev` inside the repository that gets read for your + modules. It follows the same rules for structuring as above. +- You can also use the command-line argument `--extra-module-path` to specify + the dev folder. +- Alternatively, you can set the environment variable `COMPANION_DEV_MODULES` to + the dev folder. For your convenience, you can put the following in `.env` in + your companion source folder: ``` COMPANION_DEV_MODULES= diff --git a/for-developers/module-development/module-debugging.md b/for-developers/module-development/module-debugging.md index a68984e..717fdfc 100644 --- a/for-developers/module-development/module-debugging.md +++ b/for-developers/module-development/module-debugging.md @@ -5,26 +5,36 @@ sidebar_position: 7 description: How to debug your Companion module during development. --- -Once you've started coding, debugging the code will become essential to your success. We consider it -important enough that we're covering it here before you dive into the details in the following sections. +Once you've started coding, debugging the code will become essential to your +success. We consider it important enough that we're covering it here before you +dive into the details in the following sections. -There are three main routes to debugging: log through the API, console.log, interactive debugging +There are three main routes to debugging: log through the API, console.log, +interactive debugging ## Log through the API -Companion provides individual log pages for each module that are different from the main Companion log page. +Companion provides individual log pages for each module that are different from +the main Companion log page. -You can open the module-specific log view from the connections page by clicking the button and selecting "View logs": +You can open the module-specific log view from the connections page by clicking +the +button and selecting "View logs": ![Connection debug log](./images/connection-debug-log-button.png) -The module InstanceBase class provides a logging function that allows you to specify the log-level as one of: `"info"`, `"warn"`, `"error"`, or `"debug"`. For example: +The module InstanceBase class provides a logging function that allows you to +specify the log-level as one of: `"info"`, `"warn"`, `"error"`, or `"debug"`. +For example: ```ts this.log('debug', 'My debug message.') ``` -These messages will show up in the module-specific log page and can be filtered by selecting/deselecting the "Debug" button (or whichever log-level you chose) in the top-left of the window: +These messages will show up in the module-specific log page and can be filtered +by selecting/deselecting the "Debug" button (or whichever log-level you chose) +in the top-left of the window:

> 26.01.01 00:00:00 **Module**: My debug message. @@ -36,7 +46,9 @@ The simplest debugging method is to log to the console. `console.log('your data/message');` -These messages will still show up in the module-specific log page and can be filtered by selecting/deselecting the "Console" button in the top-left of the window: +These messages will still show up in the module-specific log page and can be +filtered by selecting/deselecting the "Console" button in the top-left of the +window:

> 26.01.01 00:00:00 **Console**: your data/message @@ -44,33 +56,50 @@ These messages will still show up in the module-specific log page and can be fil :::note -Depending on buffering, several `console.log()` messages may be grouped together, so only the first will appear to have a timestamp. Use the API `this.log()` function described above, if seeing things reported in exactly the call order is important. +Depending on buffering, several `console.log()` messages may be grouped +together, so only the first will appear to have a timestamp. Use the API +`this.log()` function described above, if seeing things reported in exactly the +call order is important. ::: ## Attach a debugger -Often it can be useful and more convenient to attach a debugger to your module so you can create breakpoints from which you can inspect its state while the module is running. This method also has the advantage of not requiring the addition of numerous logging statements. +Often it can be useful and more convenient to attach a debugger to your module +so you can create breakpoints from which you can inspect its state while the +module is running. This method also has the advantage of not requiring the +addition of numerous logging statements. -To attach to your module's process, first add a file named `DEBUG-INSPECT` (no suffix) in the root of your module folder. The file can be empty or have a single number in it, which specifies the debugger port number. Next time you start Companion, it will launch your module with the remote debugging protocol enabled. +To attach to your module's process, first add a file named `DEBUG-INSPECT` (no +suffix) in the root of your module folder. The file can be empty or have a +single number in it, which specifies the debugger port number. Next time you +start Companion, it will launch your module with the remote debugging protocol +enabled. -By default Companion will pick and use a random port that will change each launch, alternatively, you can specify a port number inside the `DEBUG-INSPECT` file to use a fixed port for debugging. +By default Companion will pick and use a random port that will change each +launch, alternatively, you can specify a port number inside the `DEBUG-INSPECT` +file to use a fixed port for debugging. -You can use any compatible debugger such as the built-in VS Code debugger, or Chrome inspector to connect to your process. +You can use any compatible debugger such as the built-in VS Code debugger, or +Chrome inspector to connect to your process. :::warning -It may not be possible to debug the `init` method from your module with this, Companion still imposes the same launch timeout as usual here. But you can attach after this and see what is going on. +It may not be possible to debug the `init` method from your module with this, +Companion still imposes the same launch timeout as usual here. But you can +attach after this and see what is going on. ::: :::tip[VS Code] -VS Code users can store a setup which allows you to use F5 to initiate debugging as follows: +VS Code users can store a setup which allows you to use F5 to initiate debugging +as follows: 1. Put a port number in `DEBUG-INSPECT` -- for this example it is 12345. -2. Put the following into the file `.vscode/launch.json` (where the value of "port" matches the value in `DEBUG-INSPECT`). +2. Put the following into the file `.vscode/launch.json` (where the value of + "port" matches the value in `DEBUG-INSPECT`). ```json { diff --git a/for-developers/module-development/module-development-101.md b/for-developers/module-development/module-development-101.md index 7cf209e..54779c9 100644 --- a/for-developers/module-development/module-development-101.md +++ b/for-developers/module-development/module-development-101.md @@ -5,40 +5,88 @@ sidebar_position: 5 description: The essential overview of Companion module development. --- -With your [local environment setup](./home.md), it is time to start looking at modules in greater detail. By now you should be familiar with Git and GitHub workflows, but if not, start by reading our [GitHub Crash Course](../git-workflows/git-crashcourse.md). - -The general lifecycle of a module starts when you create a local repository as described in the [Getting Started](./home.md) page. Next you fill in the code to control your device. Finally you release it for others to use. Once you have completed one cycle, you continue by maintaining and updating your codebase. The following guide outlines the tasks you will perform to build or contribute to a module: +With your [local environment setup](./home.md), it is time to start looking at +modules in greater detail. By now you should be familiar with Git and GitHub +workflows, but if not, start by reading our +[GitHub Crash Course](../git-workflows/git-crashcourse.md). + +The general lifecycle of a module starts when you create a local repository as +described in the [Getting Started](./home.md) page. Next you fill in the code to +control your device. Finally you release it for others to use. Once you have +completed one cycle, you continue by maintaining and updating your codebase. The +following guide outlines the tasks you will perform to build or contribute to a +module: ## Name the module -If you are creating a new module, then the very first thing you'll want to do is choose a name that conforms with Companion's naming convention: _companion-module-mymanufacturer-myproduct_ (replacing _mymanufacturer-myproduct_ with appropriate names). This name will be used to name the repository itself and to fill in information in the configuration files. See the [setup instructions](./home#clone-or-copy-a-module-from-github) for more details. +If you are creating a new module, then the very first thing you'll want to do is +choose a name that conforms with Companion's naming convention: +_companion-module-mymanufacturer-myproduct_ (replacing +_mymanufacturer-myproduct_ with appropriate names). This name will be used to +name the repository itself and to fill in information in the configuration +files. See the [setup instructions](./home#clone-or-copy-a-module-from-github) +for more details. ## Configure the module -There are a few files that make up every module. Please familiarize yourself with the basic structure described in our pages on [Module Configuration](module-setup/file-structure). In particular, _package.json_, -[_companion/manifest.json_](./module-setup/manifest.json.md) and _companion/HELP.md_ define the identity of the module. Once these are defined, you will spend most of your time crafting the module source code. +There are a few files that make up every module. Please familiarize yourself +with the basic structure described in our pages on +[Module Configuration](module-setup/file-structure). In particular, +_package.json_, [_companion/manifest.json_](./module-setup/manifest.json.md) and +_companion/HELP.md_ define the identity of the module. Once these are defined, +you will spend most of your time crafting the module source code. ## Program the module -While you can handle all your module's code in one big file, we strongly recommend splitting it across several files as illustrated in our [file structure overview](./module-setup/file-structure#file-structure). +While you can handle all your module's code in one big file, we strongly +recommend splitting it across several files as illustrated in our +[file structure overview](./module-setup/file-structure#file-structure). -To understand what is needed in a module it helps to understand how the code is used. Your module is presented to Companion as a class that extends the module base class. A user can add one or more _instances_ of your module to their Companion site. When Companion starts up, it initializes each instance of the module by starting a new process and passing configuration information, as described next. +To understand what is needed in a module it helps to understand how the code is +used. Your module is presented to Companion as a class that extends the module +base class. A user can add one or more _instances_ of your module to their +Companion site. When Companion starts up, it initializes each instance of the +module by starting a new process and passing configuration information, as +described next. ### The module class and entrypoint (Module base class, configs) -In the [typical module structure](./module-setup/file-structure#file-structure), the entrypoint and module class are defined in _src/main.ts_. When your module is started, first the `constructor` of your module's class will be called, followed by your [upgrade scripts](./connection-basics/upgrade-scripts.md) and then the `init` method. - -Your constructor should only do some minimal class setup. It does not have access to the configuration information, so it should not be used to start doing things. Instead... - -The `init` method is passed any previously-stored user-config information. (The structure of the user-config is defined by you and used as the type of the generic base class.) Inside the `init` method you should initiate the connection to your device (but dont await it! Instead use the `updateStatus()` method to inform Companion asynchronously of the connection status). Here you also pass the module's actions, feedbacks, variables and presets to Companion for the first time. - -Once the module is running the `configUpdated` (but not `init`) method will be called if the user changes the config on the Connections page. (You can programmatically change the user config by calling `saveConfig()`, defined in the base class.) You can also update the action, feedback, etc. definitions at any time. - -When the module gets deleted or disabled the `destroy` function is called. here you should clean-up whatever you don't need anymore. Make sure to not leave timers running, as that can cause performance problems in companion as the leaked timers start piling up! +In the [typical module structure](./module-setup/file-structure#file-structure), +the entrypoint and module class are defined in _src/main.ts_. When your module +is started, first the `constructor` of your module's class will be called, +followed by your [upgrade scripts](./connection-basics/upgrade-scripts.md) and +then the `init` method. + +Your constructor should only do some minimal class setup. It does not have +access to the configuration information, so it should not be used to start doing +things. Instead... + +The `init` method is passed any previously-stored user-config information. (The +structure of the user-config is defined by you and used as the type of the +generic base class.) Inside the `init` method you should initiate the connection +to your device (but dont await it! Instead use the `updateStatus()` method to +inform Companion asynchronously of the connection status). Here you also pass +the module's actions, feedbacks, variables and presets to Companion for the +first time. + +Once the module is running the `configUpdated` (but not `init`) method will be +called if the user changes the config on the Connections page. (You can +programmatically change the user config by calling `saveConfig()`, defined in +the base class.) You can also update the action, feedback, etc. definitions at +any time. + +When the module gets deleted or disabled the `destroy` function is called. here +you should clean-up whatever you don't need anymore. Make sure to not leave +timers running, as that can cause performance problems in companion as the +leaked timers start piling up! ### The module functions (actions, feedback, variables, presets) -Your module provides interaction with the user by defining user-configurations, actions, feedbacks, and variables. In addition you can define "preset" buttons that predefine combinations of common actions and feedbacks for the user's convenience. These presets can be dragged onto the button grid for "instant button configuration". +Your module provides interaction with the user by defining user-configurations, +actions, feedbacks, and variables. In addition you can define "preset" buttons +that predefine combinations of common actions and feedbacks for the user's +convenience. These presets can be dragged onto the button grid for "instant +button configuration". - [Module Setup](module-setup/file-structure.md) - [Module Basics Overview](./connection-basics/overview.md) @@ -50,26 +98,41 @@ Your module provides interaction with the user by defining user-configurations, ### Log module activity (optional) -You might want to print some info or variables to the console or the in companion log both to aid in development and to help users identify what may have gone wrong +You might want to print some info or variables to the console or the in +companion log both to aid in development and to help users identify what may +have gone wrong For printing to the module debug log use: - `console.log('your data/message');` -And if you want it in the log in the web interface, see [the log method](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#log). +And if you want it in the log in the web interface, see +[the log method](https://bitfocus.github.io/companion-module-base/classes/InstanceBase.html#log). See also our instructions for [debugging your module](./module-debugging.md) ## Test the module -In any case, your module should be tested throughout at different stages of its life. -You should check the compatibility to the Companion core, especially to different versions of the configuration fields. Some users may not have used Companion in a long time and their configuration file might look different than what you expect. -And last but not least you should check **all** your actions with **all** the options and feedbacks and whatever with the real device (as much as possible). Most bugs we find are typos, which would have easily been detected by complete testing. Also please don't rely solely on simulations where possible, often the real device reacts slightly differently than the simulator. +In any case, your module should be tested throughout at different stages of its +life. You should check the compatibility to the Companion core, especially to +different versions of the configuration fields. Some users may not have used +Companion in a long time and their configuration file might look different than +what you expect. And last but not least you should check **all** your actions +with **all** the options and feedbacks and whatever with the real device (as +much as possible). Most bugs we find are typos, which would have easily been +detected by complete testing. Also please don't rely solely on simulations where +possible, often the real device reacts slightly differently than the simulator. ## Share your code -The first step in sharing your code, whether to share privately or distribute through Companion is to [package your module](./module-lifecycle/module-packaging.md). +The first step in sharing your code, whether to share privately or distribute +through Companion is to +[package your module](./module-lifecycle/module-packaging.md). -Once your packaged module has passed your quality-control and you are ready to release it publicly, you will use the [BitFocus Developer Portal](https://developer.bitfocus.io/modules/companion-connection/discover) to list it with Companion. Please follow the guide for [releasing your module](./module-lifecycle/releasing-your-module.md). +Once your packaged module has passed your quality-control and you are ready to +release it publicly, you will use the +[BitFocus Developer Portal](https://developer.bitfocus.io/modules/companion-connection/discover) +to list it with Companion. Please follow the guide for +[releasing your module](./module-lifecycle/releasing-your-module.md). Questions? Reach out on [SLACK](https://l.companion.free/q/zYXXxnGyd)! :) diff --git a/for-developers/module-development/module-lifecycle/companion-module-library.md b/for-developers/module-development/module-lifecycle/companion-module-library.md index 4a71a7b..4d82c9a 100644 --- a/for-developers/module-development/module-lifecycle/companion-module-library.md +++ b/for-developers/module-development/module-lifecycle/companion-module-library.md @@ -5,49 +5,82 @@ sidebar_position: 1 description: Explanation of the companion module library. --- -Since Companion version 3.0, we have used `@companion-module/base` and `@companion-module/tools` libraries as part of the module API. +Since Companion version 3.0, we have used `@companion-module/base` and +`@companion-module/tools` libraries as part of the module API. -The libraries are available on [npm](https://www.npmjs.com/) and are installed automatically when you run `yarn install`. +The libraries are available on [npm](https://www.npmjs.com/) and are installed +automatically when you run `yarn install`. ## What is the purpose of each library? ### @companion-module/base -This library is added as a regular dependency of your module. It contains various helpers and utilities that we think are useful to modules, as well as the main base class that your module should extend. +This library is added as a regular dependency of your module. It contains +various helpers and utilities that we think are useful to modules, as well as +the main base class that your module should extend. -If you have any suggestions for new utilities or helpers that would benefit many modules, let us know and we shall consider including it. +If you have any suggestions for new utilities or helpers that would benefit many +modules, let us know and we shall consider including it. ### @companion-module/tools -This library should be added as a devDependency of your module. It contains various bits of tooling and commands needed during the development or distribution of modules. +This library should be added as a devDependency of your module. It contains +various bits of tooling and commands needed during the development or +distribution of modules. -For example, it contains a script to bundle your module for distribution and some eslint and typescript config presets that can be used. +For example, it contains a script to bundle your module for distribution and +some eslint and typescript config presets that can be used. -We expect every module to use the build script provided from this, the rest is optional extras that you can choose to use if you like. +We expect every module to use the build script provided from this, the rest is +optional extras that you can choose to use if you like. ## When should I update them? ### @companion-module/base -The version of this library determines the versions of Companion your module can be run with. See the [version compatibility table](https://github.com/bitfocus/companion-module-base#readme). +The version of this library determines the versions of Companion your module can +be run with. See the +[version compatibility table](https://github.com/bitfocus/companion-module-base#readme). -For example, modules targeting Companion 3.0 should use @companion-module/base v1.4.3 (or any 1.x release back to v1.0.0). Modules targeting Companion 3.1 should use v1.5. A module written for 3.0 will run on 3.1, but a module written for 3.1 may not be compatible with 3.0. +For example, modules targeting Companion 3.0 should use @companion-module/base +v1.4.3 (or any 1.x release back to v1.0.0). Modules targeting Companion 3.1 +should use v1.5. A module written for 3.0 will run on 3.1, but a module written +for 3.1 may not be compatible with 3.0. -We recommend targeting the previous stable release of Companion. This will allow users who have not yet updated Companion to use the latest version of your module. But of course, you may wish to use newer versions if there are features that your module will benefit from. +We recommend targeting the previous stable release of Companion. This will allow +users who have not yet updated Companion to use the latest version of your +module. But of course, you may wish to use newer versions if there are features +that your module will benefit from. ### @companion-module/tools -This library is less picky about the version, and you will benefit by running an up to date version. +This library is less picky about the version, and you will benefit by running an +up to date version. ## Why were they created? - A bit of history -Prior to Companion version 3, modules would pull various bits of code from the Companion code. This was problematic as it meant that modules had to live in one of a few specific locations to be able to access the code. In release builds, they had to be built in before Companion was packaged. - -This was the main issue that was blocking our ability to support adding newer versions of modules into already released versions. - -Everything that modules need to access Companion is now located inside of `@companion-module/base`. Some things have not been made available, as they were determined to not be appropriate and alternatives will be recommended to the few module authors who utilised them. - -Another benefit of this separation is that it allows us to better isolate modules from being tied to specific versions of Companion. The `@companion-module/base` acts as a stable barrier between the two. It has intentionally been kept separate from the rest of the Companion code, so that changes made here get an extra level of scrutiny, as we want to guarantee backwards compatibility as much as possible. For example, in Companion version 2.x changes made to the module API occasionally required fixes to be applied to multiple modules. By having this barrier, we can avoid such problems for as long as possible, and can more easily create compatibility layers as needed. +Prior to Companion version 3, modules would pull various bits of code from the +Companion code. This was problematic as it meant that modules had to live in one +of a few specific locations to be able to access the code. In release builds, +they had to be built in before Companion was packaged. + +This was the main issue that was blocking our ability to support adding newer +versions of modules into already released versions. + +Everything that modules need to access Companion is now located inside of +`@companion-module/base`. Some things have not been made available, as they were +determined to not be appropriate and alternatives will be recommended to the few +module authors who utilised them. + +Another benefit of this separation is that it allows us to better isolate +modules from being tied to specific versions of Companion. The +`@companion-module/base` acts as a stable barrier between the two. It has +intentionally been kept separate from the rest of the Companion code, so that +changes made here get an extra level of scrutiny, as we want to guarantee +backwards compatibility as much as possible. For example, in Companion version +2.x changes made to the module API occasionally required fixes to be applied to +multiple modules. By having this barrier, we can avoid such problems for as long +as possible, and can more easily create compatibility layers as needed. ## Further reading diff --git a/for-developers/module-development/module-lifecycle/index.md b/for-developers/module-development/module-lifecycle/index.md index 51294ab..8c03bae 100644 --- a/for-developers/module-development/module-lifecycle/index.md +++ b/for-developers/module-development/module-lifecycle/index.md @@ -1,7 +1,9 @@ --- title: 'Module Development Lifecycle: Release and Maintenance' -description: The task necessary to release, maintain and upgrade a module repository over time. +description: The task necessary to release, maintain and upgrade a module repository over + time. auto_toc: 2 --- -This section describes the task necessary to package, deliver, maintain and upgrade a module repository over time. +This section describes the task necessary to package, deliver, maintain and +upgrade a module repository over time. diff --git a/for-developers/module-development/module-lifecycle/module-packaging.md b/for-developers/module-development/module-lifecycle/module-packaging.md index db10cbf..97f68a3 100644 --- a/for-developers/module-development/module-lifecycle/module-packaging.md +++ b/for-developers/module-development/module-lifecycle/module-packaging.md @@ -7,64 +7,103 @@ description: How to package your module for delivery to others. ## Background -Starting with Companion 3.0, modules must be packaged with some special tooling. This is done to reduce the number and total size of files in your module. Combining your module into just a few files can often reduce the size from multiple MB, to a few hundred KB, and lead to much shorter load times. +Starting with Companion 3.0, modules must be packaged with some special tooling. +This is done to reduce the number and total size of files in your module. +Combining your module into just a few files can often reduce the size from +multiple MB, to a few hundred KB, and lead to much shorter load times. :::warning -Sometimes the build process introduces or reveals issues that prevent the module from running, so be sure to test it before distributing. In our experience, issues often occur when working with files from disk, or introducing a new dependency that doesn't play nice. +Sometimes the build process introduces or reveals issues that prevent the module +from running, so be sure to test it before distributing. In our experience, +issues often occur when working with files from disk, or introducing a new +dependency that doesn't play nice. ::: ## Packaging for testing -If you are using one of our [recommended module templates](../module-setup/file-structure.md) you can package your module for distribution by running +If you are using one of our +[recommended module templates](../module-setup/file-structure.md) you can +package your module for distribution by running ```bash yarn companion-module-build ``` -If successful, there will now be a `pkg/` folder at your module root folder a `-.tgz` file in the root folder. The module name and version are taken from your _package.json_ file, so for example, if the module is named 'generic-animation' and the version number in _package.json_ is 0.7.0, then the file will be named _generic-animation-0.7.0.tgz_. +If successful, there will now be a `pkg/` folder at your module root folder a +`-.tgz` file in the root folder. The module name and +version are taken from your _package.json_ file, so for example, if the module +is named 'generic-animation' and the version number in _package.json_ is 0.7.0, +then the file will be named _generic-animation-0.7.0.tgz_. -If you need to debug the package code rather than the dev code, create an empty file `DEBUG-PACKAGED` in your module folder. Companion will read the code from `pkg` instead of your source folders. +If you need to debug the package code rather than the dev code, create an empty +file `DEBUG-PACKAGED` in your module folder. Companion will read the code from +`pkg` instead of your source folders. -You probably don't need to do a very thorough test, as long as it starts and connects to your device and a couple of actions work it should be fine. +You probably don't need to do a very thorough test, as long as it starts and +connects to your device and a couple of actions work it should be fine. :::tip -Due to how the packaging is done, it can result in some errors producing unreadable stack traces, or for a wall of code to be shown in the log making it unreadable. While using `DEBUG-PACKAGED`, if you run `yarn companion-module-build --dev` (the `--dev` parameter is key here) it will produce a larger build of your module that will retain original line numbers and formatting, making it much easier to read any output. +Due to how the packaging is done, it can result in some errors producing +unreadable stack traces, or for a wall of code to be shown in the log making it +unreadable. While using `DEBUG-PACKAGED`, if you run +`yarn companion-module-build --dev` (the `--dev` parameter is key here) it will +produce a larger build of your module that will retain original line numbers and +formatting, making it much easier to read any output. ::: -If you need help, don't hesitate to reach out on the Module Developer's [Slack channel](https://bfoc.us/ke7e9dqgaz) and we will be happy to assist you. +If you need help, don't hesitate to reach out on the Module Developer's +[Slack channel](https://bfoc.us/ke7e9dqgaz) and we will be happy to assist you. ## Packaging for distribution -When you run `yarn companion-module-build` (without the --dev), it produces the _.tgz_ file described above. This file contains everything a user needs to be able to run your module. A `tgz` file is like a `zip` file, but different encoding. You, or your users, can load it from the Companion Modules page and Companion will be able to run it the same as if the module came from the store. +When you run `yarn companion-module-build` (without the --dev), it produces the +_.tgz_ file described above. This file contains everything a user needs to be +able to run your module. A `tgz` file is like a `zip` file, but different +encoding. You, or your users, can load it from the Companion Modules page and +Companion will be able to run it the same as if the module came from the store. ## Customising the packaging -For more complex modules, it is possible to adjust some settings in the packaging process. +For more complex modules, it is possible to adjust some settings in the +packaging process. -Be careful when using these, as changing these settings are advanced features that can cause the build process to fail. +Be careful when using these, as changing these settings are advanced features +that can cause the build process to fail. -To start off, create a file `build-config.cjs` in your module folder, with the contents `module.exports = {}`. Each of these customisation sections will add some data to this file. +To start off, create a file `build-config.cjs` in your module folder, with the +contents `module.exports = {}`. Each of these customisation sections will add +some data to this file. ### Changing `__dirname` -Webpack has a few options for how `__dirname` behaves in packaged code. By default it gets replaced with `/` which makes everything relative to the bundled main file. Alternatively, you can set `useOriginalStructureDirname: true` and the original paths will be preserved. +Webpack has a few options for how `__dirname` behaves in packaged code. By +default it gets replaced with `/` which makes everything relative to the bundled +main file. Alternatively, you can set `useOriginalStructureDirname: true` and +the original paths will be preserved. ### Including extra data files :::tip -Since [API 1.12](../api-changes/v1.12.md), your module by default has read-only access to just your module folder, and not the whole filesystem. -You can [opt into more permissions](../connection-advanced/permissions.md) if you need it, but this will require permission from the user in the future. +Since [API 1.12](../api-changes/v1.12.md), your module by default has read-only +access to just your module folder, and not the whole filesystem. You can +[opt into more permissions](../connection-advanced/permissions.md) if you need +it, but this will require permission from the user in the future. ::: -Sometimes it can be useful to store some extra data as text files, or other formats on disk. Once your module is packaged, it wont have access to any files, from the repository unless they are JavaScript which gets included in the bundle or the files are explicitly copied. You will need to do this to allow any `fs.readFile()` or similar calls to work. +Sometimes it can be useful to store some extra data as text files, or other +formats on disk. Once your module is packaged, it wont have access to any files, +from the repository unless they are JavaScript which gets included in the bundle +or the files are explicitly copied. You will need to do this to allow any +`fs.readFile()` or similar calls to work. -You can include these files by adding something like the following to your `build-config.cjs`: +You can include these files by adding something like the following to your +`build-config.cjs`: ```js module.exports = { @@ -72,29 +111,46 @@ module.exports = { } ``` -You can use any glob pattern to define files to be copied. -All files will be copied to the root folder of the package, which is the same folder where the packaged main script is in. Make sure that there are no name conflicts when copying files from different folders. -Make sure you don't copy files you don't need, as these files will be included in the installation for all users of Companion. +You can use any glob pattern to define files to be copied. All files will be +copied to the root folder of the package, which is the same folder where the +packaged main script is in. Make sure that there are no name conflicts when +copying files from different folders. Make sure you don't copy files you don't +need, as these files will be included in the installation for all users of +Companion. ### Using native dependencies :::tip -Since [API 1.12](../api-changes/v1.12.md), you have to mark in your manifest.json that you need to do this. In the future we will use this as information for the user. -Read more about [permissions](../connection-advanced/permissions.md). +Since [API 1.12](../api-changes/v1.12.md), you have to mark in your +manifest.json that you need to do this. In the future we will use this as +information for the user. Read more about +[permissions](../connection-advanced/permissions.md). ::: -Native dependencies are not possible to bundle in the same way as js ones. So to support these requires a bit of extra work on your part. +Native dependencies are not possible to bundle in the same way as js ones. So to +support these requires a bit of extra work on your part. -It is not yet possible to use all native dependencies. We only support ones that publish prebuilt binaries as part of their npm package. -This means that some libraries are not possible to use. Reach out if you are affected by this, we would appreciate some input, and can work with you to find or fix a library to be compatible +It is not yet possible to use all native dependencies. We only support ones that +publish prebuilt binaries as part of their npm package. This means that some +libraries are not possible to use. Reach out if you are affected by this, we +would appreciate some input, and can work with you to find or fix a library to +be compatible -To support these modules, you should make one of two changes to your build-config.cjs, depending on how the library works. +To support these modules, you should make one of two changes to your +build-config.cjs, depending on how the library works. -If the library is using [`prebuild-install`](https://www.npmjs.com/package/prebuild-install), then it will not work. With `prebuild-install` it is only possible to have the binaries for one platform installed, which isn't compatible with our bundling process. If you need one of these libraries, let us know and we can try to get this working with you. +If the library is using +[`prebuild-install`](https://www.npmjs.com/package/prebuild-install), then it +will not work. With `prebuild-install` it is only possible to have the binaries +for one platform installed, which isn't compatible with our bundling process. If +you need one of these libraries, let us know and we can try to get this working +with you. -If the library is using [`pkg-prebuilds`](https://www.npmjs.com/package/pkg-prebuilds) for loading the prebuilt binaries, then you can use the following syntax. +If the library is using +[`pkg-prebuilds`](https://www.npmjs.com/package/pkg-prebuilds) for loading the +prebuilt binaries, then you can use the following syntax. ```js module.exports = { @@ -103,9 +159,12 @@ module.exports = { ``` If the library is using `node-gyp-build`, then there are a couple of options. -The preferred method is to set `useOriginalStructureDirname: true` in `build-config.cjs`. This changes the value of `__dirname` in your built module, and allows `node-gyp-build` to find its prebuilds. +The preferred method is to set `useOriginalStructureDirname: true` in +`build-config.cjs`. This changes the value of `__dirname` in your built module, +and allows `node-gyp-build` to find its prebuilds. -If you are not able to use `useOriginalStructureDirname: true`, then you can instead mark the dependency as an external: +If you are not able to use `useOriginalStructureDirname: true`, then you can +instead mark the dependency as an external: ```js module.exports = { @@ -117,15 +176,22 @@ module.exports = { } ``` -This isn't the most efficient solution, as it still results in a lot of files on disk. We are looking into whether we can package them more efficiently, but are currently blocked on how most of these dependencies locate the native portion of themselves to load. +This isn't the most efficient solution, as it still results in a lot of files on +disk. We are looking into whether we can package them more efficiently, but are +currently blocked on how most of these dependencies locate the native portion of +themselves to load. -If the library is using something else, let us know which of these approaches works, and we can update this page to include it. +If the library is using something else, let us know which of these approaches +works, and we can update this page to include it. ### Using extra plugins -Sometimes the standard webpack functionality is not enough to produce working modules for the node runtime, but there is a [webpack plugin](https://webpack.js.org/plugins/) which tackles your problem. +Sometimes the standard webpack functionality is not enough to produce working +modules for the node runtime, but there is a +[webpack plugin](https://webpack.js.org/plugins/) which tackles your problem. -You can include additional plugins by adding something like the following to your `build-config.cjs`: +You can include additional plugins by adding something like the following to +your `build-config.cjs`: ```js module.exports = { @@ -135,7 +201,8 @@ module.exports = { ### Disabling minification -Some libraries can break when minified, if they are relying on names of objects in a way that webpack doesn't expect. This can lead to cryptic runtime errors. +Some libraries can break when minified, if they are relying on names of objects +in a way that webpack doesn't expect. This can lead to cryptic runtime errors. You can disable minification (module-tools >=v1.4) with: @@ -145,17 +212,24 @@ module.exports = { } ``` -Alternatively, if you are having issues with error reports from users that have unreadable stack traces due to this minification, it can be disabled. We would prefer it to remain on for all modules to avoid bloating the install size (it can triple the size of a module), we do not mind modules enabling it if they have a reason to. +Alternatively, if you are having issues with error reports from users that have +unreadable stack traces due to this minification, it can be disabled. We would +prefer it to remain on for all modules to avoid bloating the install size (it +can triple the size of a module), we do not mind modules enabling it if they +have a reason to. ### Using worker threads -Worker threads need their own entrypoints, and so need their own built file to execute. +Worker threads need their own entrypoints, and so need their own built file to +execute. -We need to investigate how to handle this correctly. Reach out if you have ideas. +We need to investigate how to handle this correctly. Reach out if you have +ideas. ## Common issues -This process can often introduce some unexpected issues, here are some of the more common ones and solutions: +This process can often introduce some unexpected issues, here are some of the +more common ones and solutions: _TODO_ diff --git a/for-developers/module-development/module-lifecycle/releasing-your-module.md b/for-developers/module-development/module-lifecycle/releasing-your-module.md index 074fd97..a2de0d1 100644 --- a/for-developers/module-development/module-lifecycle/releasing-your-module.md +++ b/for-developers/module-development/module-lifecycle/releasing-your-module.md @@ -2,46 +2,65 @@ title: 'Releasing a Companion Module' sidebar_label: 'Release a module' sidebar_position: 3 -description: How to release your module for delivery to others using Companion's "web store". +description: How to release your module for delivery to others using Companion's "web + store". --- -Since Companion 4.0, modules get installed on demand from our API. This allows new updates to your module to get into users hands much quicker than before, as long as your module uses a compatible version of the module API. +Since Companion 4.0, modules get installed on demand from our API. This allows +new updates to your module to get into users hands much quicker than before, as +long as your module uses a compatible version of the module API. ## First Release -If this is the first release of your module, you will need to request the repository on [Slack](https://bfoc.us/ke7e9dqgaz). +If this is the first release of your module, you will need to request the +repository on [Slack](https://bfoc.us/ke7e9dqgaz). -Please post a message in the `#module-development` channel the includes your GitHub username and the desired name of your module in the `manufacturer-product` format. +Please post a message in the `#module-development` channel the includes your +GitHub username and the desired name of your module in the +`manufacturer-product` format. -Once you have a repository, and have pushed your code, you can [release a new version](#releasing-a-new-version) +Once you have a repository, and have pushed your code, you can +[release a new version](#releasing-a-new-version) ## Releasing a New Version -When a new version of your module has been tested and is ready for distribution, use the following guide to submit it for review: +When a new version of your module has been tested and is ready for distribution, +use the following guide to submit it for review: 1. **Update `package.json` version** - Use the `major.minor.patch` format (e.g., `1.2.3`). - - Refer to the [Versioning of Modules guide](../../git-workflows/versioning.md#version-of-modules) for details. + - Refer to the + [Versioning of Modules guide](../../git-workflows/versioning.md#version-of-modules) + for details. 2. **(Optional) Update `companion/manifest.json` version** - - This is not required; the build process will override this value with the version from the `package.json`. + - This is not required; the build process will override this value with the + version from the `package.json`. 3. **Create a Git tag** - Prefix the version number with `v` (e.g., `v1.2.3`). - You can create the tag by either: - - [Creating a release on GitHub](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release), or - - [Creating a local tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) and pushing it to the repository. + - [Creating a release on GitHub](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release), + or + - [Creating a local tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) + and pushing it to the repository. -4. **Submit the new version in the [Bitfocus Developer Portal](https://developer.bitfocus.io/)** (login with GitHub). +4. **Submit the new version in the + [Bitfocus Developer Portal](https://developer.bitfocus.io/)** (login with + GitHub). - In the sidebar, go to **My Connections** and select the module. - Click **Submit Version** (bottom of page). - Choose the Git Tag to submit. - (Optional) Check **Is Prerelease** if this is a beta release. - - Click **Submit** to send for review. The version status should show "Pending" after this. + - Click **Submit** to send for review. The version status should show + "Pending" after this. **Notes about the review process:** - Only versions submitted to the developer portal will be reviewed. -- Reviews are done by volunteers, so review time depends on member availability and the complexity of code changes to be reviewed. -- If adjustments are needed, you'll receive feedback through the developer portal. -- Once approved, the new version of the module becomes immediately available to download for users on Companion v4.0.0+. +- Reviews are done by volunteers, so review time depends on member availability + and the complexity of code changes to be reviewed. +- If adjustments are needed, you'll receive feedback through the developer + portal. +- Once approved, the new version of the module becomes immediately available to + download for users on Companion v4.0.0+. diff --git a/for-developers/module-development/module-lifecycle/renaming-your-module.md b/for-developers/module-development/module-lifecycle/renaming-your-module.md index 5d1a78e..ac1d16c 100644 --- a/for-developers/module-development/module-lifecycle/renaming-your-module.md +++ b/for-developers/module-development/module-lifecycle/renaming-your-module.md @@ -5,22 +5,32 @@ sidebar_position: 4 description: How to rename your module after having released it. --- -Occasionally you will need to rename a module, perhaps for example, to make the name more inclusive as you add more devices, or the manufacturer releases a new device. +Occasionally you will need to rename a module, perhaps for example, to make the +name more inclusive as you add more devices, or the manufacturer releases a new +device. -1. Ask in the module-development slack for approval on the new name - This is so that we can be sure the new name conforms to our standard structure of `companion-module-manufacturer-product` (or `companion-module-manufacturer-protocol`). +1. Ask in the module-development slack for approval on the new name This is so + that we can be sure the new name conforms to our standard structure of + `companion-module-manufacturer-product` (or + `companion-module-manufacturer-protocol`). 2. Once approved, the team will be able to rename the GitHub repository for you. -3. Some additional changes need to be made. This might be done for you, or might be left for you to do: +3. Some additional changes need to be made. This might be done for you, or might + be left for you to do: - Update the `name` and any urls in the `package.json` - Update the `name` and related fields in `companion/manifest.json` - - Add the old name to the `legacyIds` array in `companion/manifest.json`. This lets Companion know of the rename, so that existing users will be migrated across. + - Add the old name to the `legacyIds` array in `companion/manifest.json`. + This lets Companion know of the rename, so that existing users will be + migrated across. -4. Once everything is updated, you will want to publish a new version and submit that for inclusion +4. Once everything is updated, you will want to publish a new version and submit + that for inclusion :::tip -When renaming a module like this, you must not decrease the number of upgrade scripts. The count will continue from the old module name, so removing any upgrade scripts will cause new ones to be missed for many users. +When renaming a module like this, you must not decrease the number of upgrade +scripts. The count will continue from the old module name, so removing any +upgrade scripts will cause new ones to be missed for many users. ::: diff --git a/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md b/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md index fcee57b..7fd4b1b 100644 --- a/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md +++ b/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md @@ -2,27 +2,43 @@ title: 'Using a custom @companion-module/base library' sidebar_label: 'Custom @companion-module/base' sidebar_position: 8 -description: How to test and use your module with a non-release version of the companion modules. +description: How to test and use your module with a non-release version of the companion + modules. --- -Sometimes it may be useful to test or use an unreleased version of `@companion-module/base`. This commonly happens when new features are added to this library, before they are deemed ready for general use. +Sometimes it may be useful to test or use an unreleased version of +`@companion-module/base`. This commonly happens when new features are added to +this library, before they are deemed ready for general use. :::warning -Modules using unreleased versions of `@companion-module/base` should not be distributed. There will often be subtle differences between the unreleased version and the final version that will cause bugs. Make sure to only use released versions in any distributed/published module versions. +Modules using unreleased versions of `@companion-module/base` should not be +distributed. There will often be subtle differences between the unreleased +version and the final version that will cause bugs. Make sure to only use +released versions in any distributed/published module versions. ::: ## Using an unreleased version -This can sometimes be done against a normal build of companion, unless the changes to this library require changes in companion too. +This can sometimes be done against a normal build of companion, unless the +changes to this library require changes in companion too. -1. clone this repository somewhere on your computer if you havent already `git clone https://github.com/bitfocus/companion-module-base.git` +1. clone this repository somewhere on your computer if you havent already + `git clone https://github.com/bitfocus/companion-module-base.git` 2. cd into the cloned folder `cd companion-module-base` -3. If the version you want is a branch, checkout the branch, or main if you want the primary branch. eg `git checkout main` +3. If the version you want is a branch, checkout the branch, or main if you want + the primary branch. eg `git checkout main` 4. Install dependencies `yarn install` -5. Build the library `yarn build`. If this step fails with an error, you will need to resolve this -6. Make the library available through `yarn link` (if you have done this before, it can be skipped) -7. Inside your module folder, link in the local version `yarn link @companion-module/base`. This may need to be repeated anytime you run add/install/remove any dependencies from your module. - -Note: be aware that the custom version will stay with your module as you switch branches. Once you are done, the best way to ensure you are using the version defined in your `package.json` is to delete your `node_modules` folder and run `yarn install` to regenerate it +5. Build the library `yarn build`. If this step fails with an error, you will + need to resolve this +6. Make the library available through `yarn link` (if you have done this before, + it can be skipped) +7. Inside your module folder, link in the local version + `yarn link @companion-module/base`. This may need to be repeated anytime you + run add/install/remove any dependencies from your module. + +Note: be aware that the custom version will stay with your module as you switch +branches. Once you are done, the best way to ensure you are using the version +defined in your `package.json` is to delete your `node_modules` folder and run +`yarn install` to regenerate it diff --git a/for-developers/module-development/module-lifecycle/updating-nodejs.md b/for-developers/module-development/module-lifecycle/updating-nodejs.md index 4782c62..8b1f308 100644 --- a/for-developers/module-development/module-lifecycle/updating-nodejs.md +++ b/for-developers/module-development/module-lifecycle/updating-nodejs.md @@ -5,28 +5,49 @@ sidebar_position: 5 description: How to update your module to use a newer version of Node.JS. --- -Nodejs often makes new releases. In the major version jumps, these can include some breaking changes which could impact your module, so we don't want to do that without you being aware of it. +Nodejs often makes new releases. In the major version jumps, these can include +some breaking changes which could impact your module, so we don't want to do +that without you being aware of it. -Since Companion version 3.0, we've required modules to be compatible with Node.JS v18. Starting with @companion-module/base v1.11, Node.JS v22 has been supported. +Since Companion version 3.0, we've required modules to be compatible with +Node.JS v18. Starting with @companion-module/base v1.11, Node.JS v22 has been +supported. -When developing your module, you need to have a similar version of nodejs installed, for when you run `yarn`. Companion v4 supports both v18 and v22 for modules, but may provide a different minor version than you have used. +When developing your module, you need to have a similar version of nodejs +installed, for when you run `yarn`. Companion v4 supports both v18 and v22 for +modules, but may provide a different minor version than you have used. :::note -Whenever Companion runs your module, it will do so with the version of nodejs that we distribute, not the one you have installed yourself. +Whenever Companion runs your module, it will do so with the version of nodejs +that we distribute, not the one you have installed yourself. ::: -If you are using a node version manager, you can install an updated nodejs to your system, by doing something like `fnm install 22` and `fnm use 22`. See [our instructions here](../../setting-up-developer-environment.md). +If you are using a node version manager, you can install an updated nodejs to +your system, by doing something like `fnm install 22` and `fnm use 22`. See +[our instructions here](../../setting-up-developer-environment.md). ### Changing your module's version of nodejs -Companion knows what version of nodejs your module is compatible with by looking at the `companion/manifest.json` in your module. Inside the `runtime` object, is a property `type` which should be set to something like `node18` or `node22`. Currently these are the only valid values, others will be allowed in the future. If this is an unknown value, your module will fail to run when adding an instance inside Companion. +Companion knows what version of nodejs your module is compatible with by looking +at the `companion/manifest.json` in your module. Inside the `runtime` object, is +a property `type` which should be set to something like `node18` or `node22`. +Currently these are the only valid values, others will be allowed in the future. +If this is an unknown value, your module will fail to run when adding an +instance inside Companion. -Make sure that your version of the `@companion-module/base` dependency is appropriate for the version of Companion too. A table of compatibility is listed in [the readme](https://github.com/bitfocus/companion-module-base#supported-versions-of-this-library) +Make sure that your version of the `@companion-module/base` dependency is +appropriate for the version of Companion too. A table of compatibility is listed +in +[the readme](https://github.com/bitfocus/companion-module-base#supported-versions-of-this-library) -If you are using TypeScript, you should update your preset to have sensible `target` and `lib` values. The config presets in `@companion-module/tools`, have versions for each supported version of nodejs to make this easier for you. +If you are using TypeScript, you should update your preset to have sensible +`target` and `lib` values. The config presets in `@companion-module/tools`, have +versions for each supported version of nodejs to make this easier for you. -If your module has an `engines` field in the package.json, make sure that has a sensible value. +If your module has an `engines` field in the package.json, make sure that has a +sensible value. -Once you have done this, give it a test in Companion and ensure everything is working as expected. +Once you have done this, give it a test in Companion and ensure everything is +working as expected. diff --git a/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md b/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md index 8f356d6..6c41c53 100644 --- a/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md +++ b/for-developers/module-development/module-lifecycle/upgrading-a-module-built-for-companion-2.x.md @@ -7,45 +7,82 @@ description: How to update a module that was built for Companion 2 or earlier. :::danger -This guide was written over 3 years ago for an earlier version of the module api. -A majority of it will translate, but it will not be perfect match. You may want to follow this to update to the API 1.x format, then follow the newer upgrade docs for updating to the latest structure. +This guide was written over 3 years ago for an earlier version of the module +api. A majority of it will translate, but it will not be perfect match. You may +want to follow this to update to the API 1.x format, then follow the newer +upgrade docs for updating to the latest structure. ::: ## Background -In Companion 3.0, we rewrote the module-api from scratch. We chose to do this because the old api had grown very organically over 5 years, and was starting to show various issues. The main issues was modules were running in the main companion thread, and method signatures were assuming various calls to be synchronous, and modules being able to access various internals of companion (and some making concerningly large use of that ability). -Rather than trying to quickly fix up the api, it was decided to rethink it entirely. - -The general shape of the api should be familiar, but many methods names have been changed, and the whole api is written to rely on promises a lot more when before either callbacks were abused or methods would be synchronous. - -Technology has also evolved since many of the modules were written, with many of them using js syntax that was superseded in 2015! As part of this overhaul, we have imposed some minimum requirements for tooling and code style. This shouldnt be an issue, but if you run into any issues let us know on slack and we will help you out. - -Note: This guide is written assuming your module is an ES6 class (`class YourModule extends InstanceSkel {`). If it is not, then it would be best to convert it to that format first, to simplify this process. That can be done before starting this conversion for Companion 3.0, as it is supported in all older versions of companion +In Companion 3.0, we rewrote the module-api from scratch. We chose to do this +because the old api had grown very organically over 5 years, and was starting to +show various issues. The main issues was modules were running in the main +companion thread, and method signatures were assuming various calls to be +synchronous, and modules being able to access various internals of companion +(and some making concerningly large use of that ability). Rather than trying to +quickly fix up the api, it was decided to rethink it entirely. + +The general shape of the api should be familiar, but many methods names have +been changed, and the whole api is written to rely on promises a lot more when +before either callbacks were abused or methods would be synchronous. + +Technology has also evolved since many of the modules were written, with many of +them using js syntax that was superseded in 2015! As part of this overhaul, we +have imposed some minimum requirements for tooling and code style. This shouldnt +be an issue, but if you run into any issues let us know on slack and we will +help you out. + +Note: This guide is written assuming your module is an ES6 class +(`class YourModule extends InstanceSkel {`). If it is not, then it would be best +to convert it to that format first, to simplify this process. That can be done +before starting this conversion for Companion 3.0, as it is supported in all +older versions of companion ## First steps -You no longer need a developer version of companion to develop your module! It can now be done with the version you usually run, or you can keep to the old way if you prefer, but you shall have to refer to the main application development guides for getting that setup and running again. +You no longer need a developer version of companion to develop your module! It +can now be done with the version you usually run, or you can keep to the old way +if you prefer, but you shall have to refer to the main application development +guides for getting that setup and running again. -Once you have the companion launcher open, click the cog in the top right. This will reveal a 'Developer modules path' field. Use this to select a `companion-module-dev` folder you created containing your modules code. See the page on [Setting up the Development Folder](../local-modules.md) +Once you have the companion launcher open, click the cog in the top right. This +will reveal a 'Developer modules path' field. Use this to select a +`companion-module-dev` folder you created containing your modules code. See the +page on [Setting up the Development Folder](../local-modules.md) -Companion will load in any modules it finds from that folder when starting, and will restart itself whenever a file inside that folder is changed. +Companion will load in any modules it finds from that folder when starting, and +will restart itself whenever a file inside that folder is changed. -You can now clone or move or existing clone into the folder you specified for development modules. Once you have done this, launch companion and it will report your module as crashing in its status, as your code needs updating. +You can now clone or move or existing clone into the folder you specified for +development modules. Once you have done this, launch companion and it will +report your module as crashing in its status, as your code needs updating. -While developing, you can view a log for an instance in the ui. This will show all messages written with `this.log()`, `this.updateStatus()` and anything written to the console. Some of this is omitted from other logs, this is the best place to see output from your module while it is running. +While developing, you can view a log for an instance in the ui. This will show +all messages written with `this.log()`, `this.updateStatus()` and anything +written to the console. Some of this is omitted from other logs, this is the +best place to see output from your module while it is running. ![Connection debug log](../images/connection-debug-log-button.png) ### 1) Add new dependencies -To help with this new flow, any files you previously imported from companion itself (eg '../../../instance_skel') have been rewritten and are now located in a dedicated npm package. And there is a second package which provides some tooling to help with packaging your module for distribution. +To help with this new flow, any files you previously imported from companion +itself (eg '../../../instance_skel') have been rewritten and are now located in +a dedicated npm package. And there is a second package which provides some +tooling to help with packaging your module for distribution. -You can add these to your module by running `yarn add @companion-module/base -T` and `yarn add --dev @companion-module/tools` +You can add these to your module by running `yarn add @companion-module/base -T` +and `yarn add --dev @companion-module/tools` -Note: We recommend `@companion-module/base` to be installed as `~1.4` rather than `^1.4.1` as the version of this will dictate the versions of companion your module is compatible with. Read the documentation on module versioning if you want more details. +Note: We recommend `@companion-module/base` to be installed as `~1.4` rather +than `^1.4.1` as the version of this will dictate the versions of companion your +module is compatible with. Read the documentation on module versioning if you +want more details. -Add a new file (if not exist already) : `.yarnrc.yml` and put the following code in: +Add a new file (if not exist already) : `.yarnrc.yml` and put the following code +in: ```yaml nodeLinker: node-modules @@ -60,17 +97,28 @@ You should also add the following to your `.gitignore` file: ### 2) Create the companion manifest -Previously, Companion would read some special properties from your package.json file to know about your module. We have decided that we should instead be using our own file, so that we can avoid properties we do not need, and reduce ambiguation in the contents. This will also allow us to handle modules which are not node/npm based. +Previously, Companion would read some special properties from your package.json +file to know about your module. We have decided that we should instead be using +our own file, so that we can avoid properties we do not need, and reduce +ambiguation in the contents. This will also allow us to handle modules which are +not node/npm based. -To start, run the command `yarn companion-generate-manifest`. This will generate the `companion` folder based on your package.json. +To start, run the command `yarn companion-generate-manifest`. This will generate +the `companion` folder based on your package.json. -As part of the process, you should notice that the `HELP.md` file has moved into the folder too. The `HELP.md` is also expected to be inside of this folder, as well as any images it uses. +As part of the process, you should notice that the `HELP.md` file has moved into +the folder too. The `HELP.md` is also expected to be inside of this folder, as +well as any images it uses. -Please give the manifest a read, it should be fairly self explanatory. You should verify that the `runtime.entrypoint` property is a relative path to your main JavaScript file. It should have been generated correctly, but be aware that you will need to change this if you move/rename the file it references. +Please give the manifest a read, it should be fairly self explanatory. You +should verify that the `runtime.entrypoint` property is a relative path to your +main JavaScript file. It should have been generated correctly, but be aware that +you will need to change this if you move/rename the file it references. ### 3) package.json cleanup -Now that you have the new manifest, you can cleanup the old properties from your package.json. +Now that you have the new manifest, you can cleanup the old properties from your +package.json. The following properties can be removed: @@ -86,130 +134,245 @@ The following properties can be removed: - author - contributors -Note: some of these are standard npm properties, but they are no longer necessary and are defined in the manifest.json +Note: some of these are standard npm properties, but they are no longer +necessary and are defined in the manifest.json -If you have a `postinstall` script defined to build your module, that should now be removed. +If you have a `postinstall` script defined to build your module, that should now +be removed. -If you are using typescript, you can move any `@types/*` packages from dependencies to devDependencies, but this is not required. The build script should be changed from `npx rimraf dist && npx typescript@~4.5 -p tsconfig.build.json` to `rimraf dist && yarn build:main`. +If you are using typescript, you can move any `@types/*` packages from +dependencies to devDependencies, but this is not required. The build script +should be changed from +`npx rimraf dist && npx typescript@~4.5 -p tsconfig.build.json` to +`rimraf dist && yarn build:main`. -As this is quite a large change, we should update the version number too. To make the size of the change here clear, we should increment the first number in the version. For example, `1.5.11` should become `2.0.0` or `3.0.1` should become `4.0.0`. This classes it as a breaking change. Make sure to change the number in package.json, as that is the master location for that. Refer to the [Versioning of Modules guide](../../git-workflows/versioning.md#version-of-modules) for details. +As this is quite a large change, we should update the version number too. To +make the size of the change here clear, we should increment the first number in +the version. For example, `1.5.11` should become `2.0.0` or `3.0.1` should +become `4.0.0`. This classes it as a breaking change. Make sure to change the +number in package.json, as that is the master location for that. Refer to the +[Versioning of Modules guide](../../git-workflows/versioning.md#version-of-modules) +for details. ### 4) Prepare to update your code -You are now ready to begin updating your code. Many properties and methods have been renamed, so this can take some time in larger modules. But the hope is that it provides a much more consistent and easier to understand api than before. +You are now ready to begin updating your code. Many properties and methods have +been renamed, so this can take some time in larger modules. But the hope is that +it provides a much more consistent and easier to understand api than before. -Because of the amount of changes, we recommend following our steps for what to do, then to test and debug it at the very end. If you attempt to run it part way through it will most likely produce weird errors or constantly crash. +Because of the amount of changes, we recommend following our steps for what to +do, then to test and debug it at the very end. If you attempt to run it part way +through it will most likely produce weird errors or constantly crash. -Before we begin, it is recommended that you ensure you have some understanding of async & Promises in nodejs. Previously the api was very synchronous, due to everything sharing a single thread, but some methods are now asynchronous as each instance of your module is run in its own thread. It is important to understand how to use promises, as you will need that to get any values from companion, and any promises left 'floating' will crash your module. +Before we begin, it is recommended that you ensure you have some understanding +of async & Promises in nodejs. Previously the api was very synchronous, due to +everything sharing a single thread, but some methods are now asynchronous as +each instance of your module is run in its own thread. It is important to +understand how to use promises, as you will need that to get any values from +companion, and any promises left 'floating' will crash your module. TODO - write more about async or find some good tutorials/docs/examples -If you are ever unsure on how something should look, we recommend looking at the following modules. This is a curated list of up-to-date and well maintained modules. If you are still unsure, then reach out in #module-development in slack. +If you are ever unsure on how something should look, we recommend looking at the +following modules. This is a curated list of up-to-date and well maintained +modules. If you are still unsure, then reach out in #module-development in +slack. - [generic-osc](https://github.com/bitfocus/companion-module-generic-osc) - [homeassistant-server](https://github.com/bitfocus/companion-module-homeassistant-server) -Advanced users: You are now able to make your module be ESM if you wish. It is completely optional and should require no special configuration for companion. +Advanced users: You are now able to make your module be ESM if you wish. It is +completely optional and should require no special configuration for companion. -Finally, look through your code and make sure that any dependencies you use are defined in your `package.json`. Many modules have been accidentally using the dependencies that companion defined, but in this new structure that is not possible. You may need to spend some time updating your code to work with the latest version of a library, but this is a good idea to do every now and then anyway. +Finally, look through your code and make sure that any dependencies you use are +defined in your `package.json`. Many modules have been accidentally using the +dependencies that companion defined, but in this new structure that is not +possible. You may need to spend some time updating your code to work with the +latest version of a library, but this is a good idea to do every now and then +anyway. ### 5) Update your actions -If you are using typescript, `CompanionAction` and `CompanionActions` have been renamed to `CompanionActionDefinition` and `CompanionActionDefinitions` and should be imported from `'@companion-module/base'`. +If you are using typescript, `CompanionAction` and `CompanionActions` have been +renamed to `CompanionActionDefinition` and `CompanionActionDefinitions` and +should be imported from `'@companion-module/base'`. For the action definitions, the following changes have been made: - `label` has been renamed to `name` - `options` is required, but can be an empty array (`[]`) -- `callback` is now required. This is the only way an action can be executed (more help is below) - -Tip: While you are making these changes, does the value of `name` still make sense? Perhaps you could set a `description` for the action too? - -Some changes to `options` may be required, but we shall cover those in a later step, as the same changes will need to be done for feedbacks and config_fields. - -If you aren't already aware, there are some other properties you can implement if you need then. -You can find the typescript definitions as well as descriptions of each property you can set [in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/action.ts). Do let us know if anything needs more explanation/clarification. - -The `callback` property is the only way for an action to be executed. In previous versions it was possible to do this by implementing the `action()` function in the main class too. We found that using this callback made modules more maintainable as everything for an action was better grouped together, especially when the other methods are implemented. -If you need help figuring out how to convert your code from the old `action` method to these callbacks then reach out on slack. - -The parameters supplied to the `callback` or `action` function have been restructured too: - -- The second parameter has been merged into the first, with some utility methods provided in the second parameter. -- `action` has been renamed to `actionId` to be more consistent with elsewhere. This is the `id` you gave your actionDefinition. -- `deviceId` is no longer provided as we don't see a use case for why this is useful. Let us know if you have one and we shall consider re-adding it -- `bank` and `page` are no longer provided. These have been replaced by `controlId`. Actions can reside in a trigger rather than on a bank, and controlId lets us express that better. `controlId` is a unique identifier that will be the same for all actions & feedbacks on the same button or inside the same trigger, but its value should not be treated as meaningful. In a later version of companion the value of the `controlId` will change. -- The new second parameter contains an implementation of `parseVariablesInString`, this has more purpose for feedbacks, and is provided to actions for consistency - -Note: there are some properties on the object with names starting with an underscore that are not mentioned here. You must not use these, as these are temporary properties. They will be removed without notice in a future version. - -If you are using `subscribe`, `unsubscribe` or `learn`, the object parameter has changed a little, and is a subset of the properties supplied to `callback`. - -Finally, to pass the action definitions to companion has changed. It is now `this.setActionDefinitions(actions)` instead of `this.setActions(actions)` or `self.system.emit('instance_actions', self.id, actions)` +- `callback` is now required. This is the only way an action can be executed + (more help is below) + +Tip: While you are making these changes, does the value of `name` still make +sense? Perhaps you could set a `description` for the action too? + +Some changes to `options` may be required, but we shall cover those in a later +step, as the same changes will need to be done for feedbacks and config_fields. + +If you aren't already aware, there are some other properties you can implement +if you need then. You can find the typescript definitions as well as +descriptions of each property you can set +[in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/action.ts). +Do let us know if anything needs more explanation/clarification. + +The `callback` property is the only way for an action to be executed. In +previous versions it was possible to do this by implementing the `action()` +function in the main class too. We found that using this callback made modules +more maintainable as everything for an action was better grouped together, +especially when the other methods are implemented. If you need help figuring out +how to convert your code from the old `action` method to these callbacks then +reach out on slack. + +The parameters supplied to the `callback` or `action` function have been +restructured too: + +- The second parameter has been merged into the first, with some utility methods + provided in the second parameter. +- `action` has been renamed to `actionId` to be more consistent with elsewhere. + This is the `id` you gave your actionDefinition. +- `deviceId` is no longer provided as we don't see a use case for why this is + useful. Let us know if you have one and we shall consider re-adding it +- `bank` and `page` are no longer provided. These have been replaced by + `controlId`. Actions can reside in a trigger rather than on a bank, and + controlId lets us express that better. `controlId` is a unique identifier that + will be the same for all actions & feedbacks on the same button or inside the + same trigger, but its value should not be treated as meaningful. In a later + version of companion the value of the `controlId` will change. +- The new second parameter contains an implementation of + `parseVariablesInString`, this has more purpose for feedbacks, and is provided + to actions for consistency + +Note: there are some properties on the object with names starting with an +underscore that are not mentioned here. You must not use these, as these are +temporary properties. They will be removed without notice in a future version. + +If you are using `subscribe`, `unsubscribe` or `learn`, the object parameter has +changed a little, and is a subset of the properties supplied to `callback`. + +Finally, to pass the action definitions to companion has changed. It is now +`this.setActionDefinitions(actions)` instead of `this.setActions(actions)` or +`self.system.emit('instance_actions', self.id, actions)` ### 6) Updating your feedbacks -If you are using typescript, `CompanionFeedback` and `CompanionFeedbacks` have been renamed to `CompanionFeedbackDefinition` and `CompanionFeedbackDefinitions` and should be imported from `'@companion-module/base'`. +If you are using typescript, `CompanionFeedback` and `CompanionFeedbacks` have +been renamed to `CompanionFeedbackDefinition` and `CompanionFeedbackDefinitions` +and should be imported from `'@companion-module/base'`. For the feedback definitions, the following changes have been made: -- `type` is now required. If you don't have it set already, then it should be set to `'advanced'` +- `type` is now required. If you don't have it set already, then it should be + set to `'advanced'` - `label` has been renamed to `name` - `options` is required, but can be an empty array (`[]`) -- `callback` is now required. This is the only way an action can be executed (more help is below) -- If your feedback is of `type: 'boolean'` then `style` has been renamed to `defaultStyle` - -Additionally, the `rgb` and `rgbRev` methods no longer exist on your instance class. They have been renamed to `combineRgb` and `splitRgb` and should be imported from `'@companion-module/base'`. - -Tip: While you are making these changes, does the value of `name` still make sense? Perhaps you could set a `description` for the action too? - -Some changes to `options` may be required, but we shall cover those in a later step, as the same changes will need to be done for feedbacks and config_fields. - -If you aren't already aware, there are some other properties you can implement if you need then. -You can find the typescript definitions as well as descriptions of each property you can set [in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/feedback.ts). Do let us know if anything needs more explanation/clarification. - -The `callback` property is the only way for an feedback to be checked. In previous versions it was possible to do this by implementing the `feedback()` function in the main class too. We found that using this callback made modules more maintainable as everything for a feedback was better grouped together, especially when the other methods are implemented. -If you need help figuring out how to convert your code from the old `feedback` method to these callbacks then reach out on slack. - -The parameters supplied to the `callback` or `feedback` function have been restructured too: - -- The parameters have been merged into one, with some utility methods provided in the second parameter. -- `type` has been renamed to `feedbackId` to be more consistent with elsewhere. This is the `id` you gave your feedbackDefinition. -- `bank` and `page` are no longer provided. These have been replaced by `controlId`. Feedbacks can reside in a trigger rather than on a bank, and controlId lets us express that better. `controlId` is a unique identifier that will be the same for all actions & feedbacks on the same button or inside the same trigger, but its value should not be treated as meaningful. In a later version of companion the value of the `controlId` will change. -- It is no longer possible to get the complete 'bank' object that was provided before. Do let us know if you have a use case for it, we couldn't think of one. -- For 'advanced' feedbacks, the `width` and `height` properties are now represented by a single `image` property. This helps clarify when they will be defined. Also note that these may not be present for all feedbacks in a future version. -- The new second parameter contains an implementation of `parseVariablesInString`. You **must** use this instead of the similar method on the class, otherwise your feedback will not be rechecked when the variables change. - -Note: there are some properties on the object with names starting with an underscore that are not mentioned here. You must not use these, as these are temporary properties. They will be removed without notice in a future version. - -If you are using `subscribe`, `unsubscribe` or `learn`, the object parameter has changed a little, and is a subset of the properties supplied to `callback`. +- `callback` is now required. This is the only way an action can be executed + (more help is below) +- If your feedback is of `type: 'boolean'` then `style` has been renamed to + `defaultStyle` + +Additionally, the `rgb` and `rgbRev` methods no longer exist on your instance +class. They have been renamed to `combineRgb` and `splitRgb` and should be +imported from `'@companion-module/base'`. + +Tip: While you are making these changes, does the value of `name` still make +sense? Perhaps you could set a `description` for the action too? + +Some changes to `options` may be required, but we shall cover those in a later +step, as the same changes will need to be done for feedbacks and config_fields. + +If you aren't already aware, there are some other properties you can implement +if you need then. You can find the typescript definitions as well as +descriptions of each property you can set +[in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/feedback.ts). +Do let us know if anything needs more explanation/clarification. + +The `callback` property is the only way for an feedback to be checked. In +previous versions it was possible to do this by implementing the `feedback()` +function in the main class too. We found that using this callback made modules +more maintainable as everything for a feedback was better grouped together, +especially when the other methods are implemented. If you need help figuring out +how to convert your code from the old `feedback` method to these callbacks then +reach out on slack. + +The parameters supplied to the `callback` or `feedback` function have been +restructured too: + +- The parameters have been merged into one, with some utility methods provided + in the second parameter. +- `type` has been renamed to `feedbackId` to be more consistent with elsewhere. + This is the `id` you gave your feedbackDefinition. +- `bank` and `page` are no longer provided. These have been replaced by + `controlId`. Feedbacks can reside in a trigger rather than on a bank, and + controlId lets us express that better. `controlId` is a unique identifier that + will be the same for all actions & feedbacks on the same button or inside the + same trigger, but its value should not be treated as meaningful. In a later + version of companion the value of the `controlId` will change. +- It is no longer possible to get the complete 'bank' object that was provided + before. Do let us know if you have a use case for it, we couldn't think of + one. +- For 'advanced' feedbacks, the `width` and `height` properties are now + represented by a single `image` property. This helps clarify when they will be + defined. Also note that these may not be present for all feedbacks in a future + version. +- The new second parameter contains an implementation of + `parseVariablesInString`. You **must** use this instead of the similar method + on the class, otherwise your feedback will not be rechecked when the variables + change. + +Note: there are some properties on the object with names starting with an +underscore that are not mentioned here. You must not use these, as these are +temporary properties. They will be removed without notice in a future version. + +If you are using `subscribe`, `unsubscribe` or `learn`, the object parameter has +changed a little, and is a subset of the properties supplied to `callback`. ### 7) Updating your presets -If you are using typescript, `CompanionPreset` has been renamed to `CompanionButtonPresetDefinition`. There is also a `CompanionPresetDefinitions` defining a collection of these objects. +If you are using typescript, `CompanionPreset` has been renamed to +`CompanionButtonPresetDefinition`. There is also a `CompanionPresetDefinitions` +defining a collection of these objects. -The first change to be aware of, is that the `setPresetDefinitions()` function is now expecting an object of presets, rather than array. This is for better consistency with actions and feedbacks, and also provides a unique id for each preset. +The first change to be aware of, is that the `setPresetDefinitions()` function +is now expecting an object of presets, rather than array. This is for better +consistency with actions and feedbacks, and also provides a unique id for each +preset. For the preset definitions, the following changes have been made for both types: - `type` is a new property that must be `button` - `label` has been renamed to `name` -- `options` is a new property of some behavioural properties for the button. Its contents is explained below. -- `bank` has been renamed to `style`. Additionally some properties have been moved out of this object, listed below. +- `options` is a new property of some behavioural properties for the button. Its + contents is explained below. +- `bank` has been renamed to `style`. Additionally some properties have been + moved out of this object, listed below. - `bank.style` has been removed - `bank.relative_delay` has been moved to `options.relativeDelay` -- `bank.latch` has been removed. This will be handled below when changing the actions -- `feedbacks` The objects inside this have changed slightly. The `type` property has been renamed to `feedbackId`, for better consistency. -- `actions` and `release_actions` have been combined into `steps`, the exact structure is documented below. - -Note: Even when there are no actions or feedbacks, you would need to put those objects in : `feedbacks: []` & `steps: []`. - -Note: Remember that the `rgb` and `rgbRev` methods no longer exist on your instance class. They have been renamed to `combineRgb` and `splitRgb` and should be imported from `'@companion-module/base'`. - -The latch button mode has been replaced with a more flexible 'stepped' system. On each button, you can have as many steps as you wish, each with their own down/up/rotate actions. When releasing the button, it will by default automatically progress to the next step, or you can disable that and use an internal action to change the current step of a button. -While is is wordier and more complex to make a latched button, this allows for much more complex flows, such as using another button as a 'shift' key, or having one 'go' button which runs the whole pre-programmed show. - -The `steps` property is an array of objects. Each object should be at a minimum `{ down: [], up: [] }` (`rotate_left` and `rotate_right` are also valid here). +- `bank.latch` has been removed. This will be handled below when changing the + actions +- `feedbacks` The objects inside this have changed slightly. The `type` property + has been renamed to `feedbackId`, for better consistency. +- `actions` and `release_actions` have been combined into `steps`, the exact + structure is documented below. + +Note: Even when there are no actions or feedbacks, you would need to put those +objects in : `feedbacks: []` & `steps: []`. + +Note: Remember that the `rgb` and `rgbRev` methods no longer exist on your +instance class. They have been renamed to `combineRgb` and `splitRgb` and should +be imported from `'@companion-module/base'`. + +The latch button mode has been replaced with a more flexible 'stepped' system. +On each button, you can have as many steps as you wish, each with their own +down/up/rotate actions. When releasing the button, it will by default +automatically progress to the next step, or you can disable that and use an +internal action to change the current step of a button. While is is wordier and +more complex to make a latched button, this allows for much more complex flows, +such as using another button as a 'shift' key, or having one 'go' button which +runs the whole pre-programmed show. + +The `steps` property is an array of objects. Each object should be at a minimum +`{ down: [], up: [] }` (`rotate_left` and `rotate_right` are also valid here). For example, a normal button will only have one step: @@ -239,17 +402,22 @@ steps: [ ] ``` -For the action objects inside of each of these steps, the `action` property renamed to `actionId`, for better consistency with elsewhere. +For the action objects inside of each of these steps, the `action` property +renamed to `actionId`, for better consistency with elsewhere. ### 8) Updating options and config fields -The options/input fields available to use as options for actions and feedbacks, as well as for your config fields has changed a little. +The options/input fields available to use as options for actions and feedbacks, +as well as for your config fields has changed a little. -There may be additional new properties not listed here. You can check [the docs](../connection-basics/input-field-types.md) for full details on the available input fields. +There may be additional new properties not listed here. You can check +[the docs](../connection-basics/input-field-types.md) for full details on the +available input fields. #### common changes -The optional `isVisible` function has changed, its parameter is now the options object for the action/feedback, not the whole action/feedback object +The optional `isVisible` function has changed, its parameter is now the options +object for the action/feedback, not the whole action/feedback object #### text @@ -257,7 +425,8 @@ The `text` type has been renamed to `static-text` #### textinput & textwithvariables -These have been combined into one `textinput`. With a new `useVariables` property to select the mode. +These have been combined into one `textinput`. With a new `useVariables` +property to select the mode. #### dropdown @@ -279,23 +448,30 @@ These are unchanged #### Anything else -That should be all of them, if you have something else then it has likely been forgotten/removed. +That should be all of them, if you have something else then it has likely been +forgotten/removed. Either use a supported input type or let us know what we missed. ### 9) Updating variables -If you are using typescript, `CompanionVariable` has been renamed to `CompanionVariableDefinition` and should be imported from `'@companion-module/base'`. +If you are using typescript, `CompanionVariable` has been renamed to +`CompanionVariableDefinition` and should be imported from +`'@companion-module/base'`. For the variable definitions, the following changes have been made: - `name` has been renamed to `variableId` - `label` has been renamed to `name` -We acknowledge that this change is rather confusing, but it felt necessary for consistency with elsewhere +We acknowledge that this change is rather confusing, but it felt necessary for +consistency with elsewhere -To set the value of variables, the `setVariables` method has been renamed to `setVariableValues`, and the `setVariable` method has been removed. -This is to encourage multiple values to be set in the one call which will make companion more responsive by being able to process multiple changes at a time. Please try to combine calls to `setVariableValues` where possible. +To set the value of variables, the `setVariables` method has been renamed to +`setVariableValues`, and the `setVariable` method has been removed. This is to +encourage multiple values to be set in the one call which will make companion +more responsive by being able to process multiple changes at a time. Please try +to combine calls to `setVariableValues` where possible. For example, before: @@ -317,14 +493,19 @@ this.setVariableValues({ ### 10) Updating upgrade-scripts -If you are using typescript, `CompanionStaticUpgradeScript` should be imported from `'@companion-module/base'`. +If you are using typescript, `CompanionStaticUpgradeScript` should be imported +from `'@companion-module/base'`. -If you are using the `CreateConvertToBooleanFeedbackUpgradeScript` helper method on the InstanceSkel, this has moved and should be imported from `'@companion-module/base'`. +If you are using the `CreateConvertToBooleanFeedbackUpgradeScript` helper method +on the InstanceSkel, this has moved and should be imported from +`'@companion-module/base'`. -The upgrade script parameters and return value have been completely reworked, as the old functions did not fit into the new flow well. +The upgrade script parameters and return value have been completely reworked, as +the old functions did not fit into the new flow well. -The first parameter (`context`) to the functions remains, but currently has no methods. We expect to add some methods in the future. -The remaining parameters have been combined into a single `props` object. +The first parameter (`context`) to the functions remains, but currently has no +methods. We expect to add some methods in the future. The remaining parameters +have been combined into a single `props` object. This object is composed as @@ -336,11 +517,14 @@ This object is composed as } ``` -Tip: These upgrade scripts can be called at any time. They can be called to upgrade existing configuration, or when data is imported into companion. +Tip: These upgrade scripts can be called at any time. They can be called to +upgrade existing configuration, or when data is imported into companion. -At times the config property will be null, if the config does not need updating. There may be no actions or no feedbacks, depending on what needs upgrading. +At times the config property will be null, if the config does not need updating. +There may be no actions or no feedbacks, depending on what needs upgrading. -Previously, the return type was simply `boolean`, to state whether anything had changed. The return type is now expected to be an object of the format: +Previously, the return type was simply `boolean`, to state whether anything had +changed. The return type is now expected to be an object of the format: ```js { @@ -350,83 +534,135 @@ Previously, the return type was simply `boolean`, to state whether anything had } ``` -If an action or feedback is not included in the output type, then it is assumed to not have been changed and any changes you have made to the object passed in will be lost. -If `updatedConfig` is not set, then it is assumed that the config has not changed, and any changes will be lost. +If an action or feedback is not included in the output type, then it is assumed +to not have been changed and any changes you have made to the object passed in +will be lost. If `updatedConfig` is not set, then it is assumed that the config +has not changed, and any changes will be lost. -This allows companion to better understand what has changed in an optimal way, and also allows you more flexibility in your code as you are no longer forced to update in place. +This allows companion to better understand what has changed in an optimal way, +and also allows you more flexibility in your code as you are no longer forced to +update in place. Tip: Make sure you don't change the id fields, or it won't track the changes! -The config object is the same as you receive in the module, and is the same as before. +The config object is the same as you receive in the module, and is the same as +before. -The action and feedback objects have a similar shape to how they are provided to their callbacks. You can see more about the exact structure of the objects [in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/upgrade.ts). This is harder to document the changes, and upgrade scripts are not that widely used. +The action and feedback objects have a similar shape to how they are provided to +their callbacks. You can see more about the exact structure of the objects +[in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/src/module-api/upgrade.ts). +This is harder to document the changes, and upgrade scripts are not that widely +used. -Finally, these are no longer provided via the static method. They will be passed into a function call later described later on. We suggest making them an array outside of the class that can be used later on. +Finally, these are no longer provided via the static method. They will be passed +into a function call later described later on. We suggest making them an array +outside of the class that can be used later on. ### 11) Updating any uses of the TCP/UDP/Telnet helpers -If you are importing the old socket helpers, you will need to make some changes to handle some changes that have been made to them. +If you are importing the old socket helpers, you will need to make some changes +to handle some changes that have been made to them. #### UDP -This should be imported as `UDPHelper` from `@companion-module/base` instead of the old path. +This should be imported as `UDPHelper` from `@companion-module/base` instead of +the old path. Most usage of the class is the same, only the differences are documented: -- The `addMembership` method has been removed. It was previously broken and appeared unused by any module. If you have need for it, it can be reimplemented -- The `send` method no longer accepts a callback. Instead it returns a promise that must be handled. -- The `status_change` event emits different statuses, to match how they have changed elsewhere. It now emits `'ok' | 'unknown_error'` +- The `addMembership` method has been removed. It was previously broken and + appeared unused by any module. If you have need for it, it can be + reimplemented +- The `send` method no longer accepts a callback. Instead it returns a promise + that must be handled. +- The `status_change` event emits different statuses, to match how they have + changed elsewhere. It now emits `'ok' | 'unknown_error'` - There are some new readonly properties added: `isDestroyed` -- Any previously visible class members have been hidden. If you rely on any, let us know and we shall look at extending the wrapper or making things public again +- Any previously visible class members have been hidden. If you rely on any, let + us know and we shall look at extending the wrapper or making things public + again #### TCP -This should be imported as `TCPHelper` from `@companion-module/base` instead of the old path. +This should be imported as `TCPHelper` from `@companion-module/base` instead of +the old path. Most usage of the class is the same, only the differences are documented: -- The `send` method no longer accepts a callback. Instead it returns a promise that must be handled. -- The `status_change` event emits different statuses, to match how they have changed elsewhere. It now emits `'ok' | 'connecting' | 'disconnected' | 'unknown_error'` -- There are some new readonly properties added: `isConnected`, `isConnecting` and `isDestroyed` -- The `write` and `send` methods have been combined into a single `send` method. Behaviour is the same, just the name has changed -- Any previously visible class members have been hidden. If you rely on any, let us know and we shall look at extending the wrapper or making things public again +- The `send` method no longer accepts a callback. Instead it returns a promise + that must be handled. +- The `status_change` event emits different statuses, to match how they have + changed elsewhere. It now emits + `'ok' | 'connecting' | 'disconnected' | 'unknown_error'` +- There are some new readonly properties added: `isConnected`, `isConnecting` + and `isDestroyed` +- The `write` and `send` methods have been combined into a single `send` method. + Behaviour is the same, just the name has changed +- Any previously visible class members have been hidden. If you rely on any, let + us know and we shall look at extending the wrapper or making things public + again #### Telnet -This should be imported as `TelnetHelper` from `@companion-module/base` instead of the old path. +This should be imported as `TelnetHelper` from `@companion-module/base` instead +of the old path. Most usage of the class is the same, only the differences are documented: -- The `send` method no longer accepts a callback. Instead it returns a promise that must be handled. -- The `status_change` event emits different statuses, to match how they have changed elsewhere. It now emits `'ok' | 'connecting' | 'disconnected' | 'unknown_error'` -- There are some new readonly properties added: `isConnected`, `isConnecting` and `isDestroyed` -- The `write` and `send` methods have been combined into a single `send` method. Behaviour is the same, just the name has changed -- Any previously visible class members have been hidden. If you rely on any, let us know and we shall look at extending the wrapper or making things public again +- The `send` method no longer accepts a callback. Instead it returns a promise + that must be handled. +- The `status_change` event emits different statuses, to match how they have + changed elsewhere. It now emits + `'ok' | 'connecting' | 'disconnected' | 'unknown_error'` +- There are some new readonly properties added: `isConnected`, `isConnecting` + and `isDestroyed` +- The `write` and `send` methods have been combined into a single `send` method. + Behaviour is the same, just the name has changed +- Any previously visible class members have been hidden. If you rely on any, let + us know and we shall look at extending the wrapper or making things public + again ### 12) Updating your main class Finally, we are ready to look at your main class. -To start, you should change your class to extend `InstanceBase`, which can be imported from `@companion-module/base`. - -There are a few fundamental changes to `InstanceBase` compared to the old `InstanceSkel`. - -- You should be doing very little in the constructor. You do not have the config for the instance at this point, or the ability to call any companion methods here. The intention is to make sure various class properties are defined here, with the module truly starting to work in the `init()` method. -- `this.config` is no longer provided for you by the base class. You are provided a new config object in `init()` and `updateConfig()`, it is up to you to to an `this.config = config` when receiving that, or to do something else with the config object. -- `this.system` is no longer available. That was previously an internal api that too many modules were hooking into. This caused many of them to break at unexpected times, and is no longer possible in this new api. If we haven't exposed something you are using on system as a proper method on `InstanceBase`, then do let us know on slack or github, and we will either implement it or help you with an alternative. - -The constructor has changed to have a single parameter called `internal`. This is of typescript type `unknown`. You must not use this object for anything yourself, the value of this is an internal detail, and will change in unexpected ways without notice. -You should start your constructor with the following +To start, you should change your class to extend `InstanceBase`, which can be +imported from `@companion-module/base`. + +There are a few fundamental changes to `InstanceBase` compared to the old +`InstanceSkel`. + +- You should be doing very little in the constructor. You do not have the config + for the instance at this point, or the ability to call any companion methods + here. The intention is to make sure various class properties are defined here, + with the module truly starting to work in the `init()` method. +- `this.config` is no longer provided for you by the base class. You are + provided a new config object in `init()` and `updateConfig()`, it is up to you + to to an `this.config = config` when receiving that, or to do something else + with the config object. +- `this.system` is no longer available. That was previously an internal api that + too many modules were hooking into. This caused many of them to break at + unexpected times, and is no longer possible in this new api. If we haven't + exposed something you are using on system as a proper method on + `InstanceBase`, then do let us know on slack or github, and we will either + implement it or help you with an alternative. + +The constructor has changed to have a single parameter called `internal`. This +is of typescript type `unknown`. You must not use this object for anything +yourself, the value of this is an internal detail, and will change in unexpected +ways without notice. You should start your constructor with the following ```js constructor(internal) { super(internal) ``` -Remember that you do not have access to the config here, you may need to move some stuff into `init()` +Remember that you do not have access to the config here, you may need to move +some stuff into `init()` -Hopefully you have an understanding of async code, because we now need to start using it. -It is expected that `init()` will return a Promise. The simplest way to do this is to mark it as async. +Hopefully you have an understanding of async code, because we now need to start +using it. It is expected that `init()` will return a Promise. The simplest way +to do this is to mark it as async. ```js async init(config) { @@ -434,47 +670,76 @@ It is expected that `init()` will return a Promise. The simplest way to do this `init()` also has a parameter, of your config object. -Inside of init, you are free to do things as you wish. But make sure that any method returning a promise isn't left floating, so that errors propagate correctly. - -Tip: if you do a `this.checkFeedbacks()` inside of `init()`, you can remove that line - -The method `config_fields` should be renamed to `getConfigFields`. -The method `updateConfig` should be renamed to `configUpdated`, it too is expected to return a Promise and should also be marked as async. -The method `destroy` is expected to return a Promise and should also be marked as async. - -If you have a method called `action` or `feedback` still, make sure it has been migrated fully in the earlier steps, then remove it as it will no longer be called. - -Some other methods provided by companion have been changed. -Any where the name starts with an underscore must not be used as they are internal methods that will change without notice. - -- The static method `CreateConvertToBooleanFeedbackUpgradeScript` has been removed and can be imported from `@companion-module/base` instead -- The method `saveConfig` now expects a parameter of the config object to be saved -- The method `setActions` has been renamed to `setActionDefinitions`, as explained earlier -- The method `setPresetDefinitions` now expects an object of presets, as explained earlier -- The method `setVariables` has been renamed to `setVariableValues`, as explained earlier +Inside of init, you are free to do things as you wish. But make sure that any +method returning a promise isn't left floating, so that errors propagate +correctly. + +Tip: if you do a `this.checkFeedbacks()` inside of `init()`, you can remove that +line + +The method `config_fields` should be renamed to `getConfigFields`. The method +`updateConfig` should be renamed to `configUpdated`, it too is expected to +return a Promise and should also be marked as async. The method `destroy` is +expected to return a Promise and should also be marked as async. + +If you have a method called `action` or `feedback` still, make sure it has been +migrated fully in the earlier steps, then remove it as it will no longer be +called. + +Some other methods provided by companion have been changed. Any where the name +starts with an underscore must not be used as they are internal methods that +will change without notice. + +- The static method `CreateConvertToBooleanFeedbackUpgradeScript` has been + removed and can be imported from `@companion-module/base` instead +- The method `saveConfig` now expects a parameter of the config object to be + saved +- The method `setActions` has been renamed to `setActionDefinitions`, as + explained earlier +- The method `setPresetDefinitions` now expects an object of presets, as + explained earlier +- The method `setVariables` has been renamed to `setVariableValues`, as + explained earlier - The method `setVariable` has been removed, as explained earlier - The method `getVariable` has been renamed to `getVariableValue`. -- The method `checkFeedbacks` now accepts multiple feedbacks to check. eg `this.checkFeedbacks('one', 'two', 'three')` -- The method `parseVariables` has been renamed to `parseVariablesInString`. Note that this method returns a promise instead of accepting a callback. +- The method `checkFeedbacks` now accepts multiple feedbacks to check. eg + `this.checkFeedbacks('one', 'two', 'three')` +- The method `parseVariables` has been renamed to `parseVariablesInString`. Note + that this method returns a promise instead of accepting a callback. - The method `getAllFeedbacks` has been removed, with no replacement - The method `getAllActions` has been removed, with no replacement - The method `oscSend` is unchanged -- The method `status` has been renamed to `updateStatus`. Additionally, the first parameter has been changed and should be provided a string with one of the values from below. The second parameter remains as an optional string for more details. Note: calls to this also now add a log line when the status changes. +- The method `status` has been renamed to `updateStatus`. Additionally, the + first parameter has been changed and should be provided a string with one of + the values from below. The second parameter remains as an optional string for + more details. Note: calls to this also now add a log line when the status + changes. - The method `log` is unchanged. - The method `debug` has been removed, use `log` instead -- The methods `rgb` and `rgbRev` have been removed. They can be imported as `combineRgb` and `splitRgb` from `@companion-module/base` instead +- The methods `rgb` and `rgbRev` have been removed. They can be imported as + `combineRgb` and `splitRgb` from `@companion-module/base` instead - The `STATUS_*` properties have been removed, they are no longer useful -- The `REGEX_*` properties have been removed. Instead you can import `Regex` from `@companion-module/base` and use them from there. -- The method `defineConst` has been removed. Instead you can either define it as a constant variable outside your class `const YOUR_THING = value` (perhaps in a separate constants.js file?) or as a normal member variable `this.YOUR_THING = value` +- The `REGEX_*` properties have been removed. Instead you can import `Regex` + from `@companion-module/base` and use them from there. +- The method `defineConst` has been removed. Instead you can either define it as + a constant variable outside your class `const YOUR_THING = value` (perhaps in + a separate constants.js file?) or as a normal member variable + `this.YOUR_THING = value` - Anything else? It has likely been removed or forgotten. Ask us on slack -Possible values for status: 'ok', 'connecting', 'disconnected', 'connection_failure', 'bad_config', 'unknown_error', 'unknown_warning' -Note: More will be added in the future, let us know if you have any ideas for common statuses. +Possible values for status: 'ok', 'connecting', 'disconnected', +'connection_failure', 'bad_config', 'unknown_error', 'unknown_warning' Note: +More will be added in the future, let us know if you have any ideas for common +statuses. -Once you have made sure that any method calls to methods exposed on InstanceBase have been updated, there is only a little bit more. +Once you have made sure that any method calls to methods exposed on InstanceBase +have been updated, there is only a little bit more. -At the bottom of your file you should find a line looking something like `export = MyInstance`. -You should replace this line with `runEntrypoint(MyInstance, UpgradeScripts)`, making sure to pass your class as the first parameter, and your array of upgrade scripts to the second. If you have no upgrade scripts then make the second parameter be `[]`. +At the bottom of your file you should find a line looking something like +`export = MyInstance`. You should replace this line with +`runEntrypoint(MyInstance, UpgradeScripts)`, making sure to pass your class as +the first parameter, and your array of upgrade scripts to the second. If you +have no upgrade scripts then make the second parameter be `[]`. Congratulations. You have now converted all of your code! @@ -482,44 +747,80 @@ It is time to take a break, as next we shall be running and testing it. ### 13) Run it and debug! -Startup companion, and make sure you have it setup so that it will find your custom module. +Startup companion, and make sure you have it setup so that it will find your +custom module. If all went well, then your module will run and connect to your device. -If it does not, hopefully you can figure out what has broken. There are too many possibilities for us to document here, but we can try to document some common issues. +If it does not, hopefully you can figure out what has broken. There are too many +possibilities for us to document here, but we can try to document some common +issues. -Once it is running, make sure to test every action, feedback, variable and preset. It is easy to make a mistake during the upgrading process. Whatever bugs you find now means less to be found by other users. +Once it is running, make sure to test every action, feedback, variable and +preset. It is easy to make a mistake during the upgrading process. Whatever bugs +you find now means less to be found by other users. -When you are happy with it being stable enough for others to test, let us know and we shall include it in the beta builds. +When you are happy with it being stable enough for others to test, let us know +and we shall include it in the beta builds. ### 14) Package it and test -For modules in this new format, we require them to be packaged with some special tooling. This is done to both reduce the number of files that your module spans on disk, and also the size. Loading code spread across hundreds of files is surprisingly slow on some OSes, any by combining it all into a few files, we can often reduce the size from multiple MB, to a few hundred KB. - -During the build process of the releases your module package will be generated automatically and bundled with the application, so you have to make sure that the final package is working. If you are developing with a complete dev environment, it is not sufficient if your module works in the dev environment. - -Sometimes once built there are issues that prevent a package from running, so it is mandatory to test it before distributing it. In our experience, issues often occur when working with files from disk, or introducing a new dependency that doesn't play nice. Once you have done this once, if you are just changing some internal logic you probably don't need to repeat this unless you want to be sure. - -You can build your module into this format with `yarn companion-module-build`. If this was successful, there should now be a `pkg` folder and a `pkg.tgz` file. These both contain the build version of your module! -If you create an empty file `DEBUG-PACKAGED` in your module folder, then companion will read the code from `pkg` instead. This will let you test it. -You probably don't need to do a very thorough test, as long as it starts and connects to your device and a couple of actions work it should be fine. - -Make sure to remove this `DEBUG-PACKAGED` file once you are done testing it, or next time you try to update your module it will keep loading the copy from `pkg`! - -If you encountered any issues in this process that you need help with, then have a look at the [Module packaging](./module-packaging.md) page for additional tips. +For modules in this new format, we require them to be packaged with some special +tooling. This is done to both reduce the number of files that your module spans +on disk, and also the size. Loading code spread across hundreds of files is +surprisingly slow on some OSes, any by combining it all into a few files, we can +often reduce the size from multiple MB, to a few hundred KB. + +During the build process of the releases your module package will be generated +automatically and bundled with the application, so you have to make sure that +the final package is working. If you are developing with a complete dev +environment, it is not sufficient if your module works in the dev environment. + +Sometimes once built there are issues that prevent a package from running, so it +is mandatory to test it before distributing it. In our experience, issues often +occur when working with files from disk, or introducing a new dependency that +doesn't play nice. Once you have done this once, if you are just changing some +internal logic you probably don't need to repeat this unless you want to be +sure. + +You can build your module into this format with `yarn companion-module-build`. +If this was successful, there should now be a `pkg` folder and a `pkg.tgz` file. +These both contain the build version of your module! If you create an empty file +`DEBUG-PACKAGED` in your module folder, then companion will read the code from +`pkg` instead. This will let you test it. You probably don't need to do a very +thorough test, as long as it starts and connects to your device and a couple of +actions work it should be fine. + +Make sure to remove this `DEBUG-PACKAGED` file once you are done testing it, or +next time you try to update your module it will keep loading the copy from +`pkg`! + +If you encountered any issues in this process that you need help with, then have +a look at the [Module packaging](./module-packaging.md) page for additional +tips. ### 15) Feedback -Have any thoughts/feedback on this process? Anything in the docs that should be improved? Do [let us know](https://github.com/bitfocus/companion-module-base/issues), we are interested in your feedback! -We won't be able to cater to everything you dislike about the changes, as other modules are already using these new apis, but perhaps we can make the transition smoother? +Have any thoughts/feedback on this process? Anything in the docs that should be +improved? Do +[let us know](https://github.com/bitfocus/companion-module-base/issues), we are +interested in your feedback! We won't be able to cater to everything you dislike +about the changes, as other modules are already using these new apis, but +perhaps we can make the transition smoother? -Have an idea of a new connection helper that would be beneficial to you? Or have some utility code that you are copying into multiple modules? We are interested to hear this. We are happy to add more to `@companion-module/base` if it will be useful to many modules and is unlikely to result in breaking changes. +Have an idea of a new connection helper that would be beneficial to you? Or have +some utility code that you are copying into multiple modules? We are interested +to hear this. We are happy to add more to `@companion-module/base` if it will be +useful to many modules and is unlikely to result in breaking changes. -We appreciate that this update is throwing a lot of changes at you, but changes of this scale are a rare occurrence and shouldn't be necessary to repeat for at least another 5 years. +We appreciate that this update is throwing a lot of changes at you, but changes +of this scale are a rare occurrence and shouldn't be necessary to repeat for at +least another 5 years. ### 16) Follow up recommendations -There are some extra steps that we recommend modules take, but are completely optional. +There are some extra steps that we recommend modules take, but are completely +optional. - [Setting up code formatting](../module-setup/code-quality.md) - [Reusable TypeScript config](../module-setup/typescript-config.md) diff --git a/for-developers/module-development/module-setup/code-quality.md b/for-developers/module-development/module-setup/code-quality.md index 72755d2..1d6f1ef 100644 --- a/for-developers/module-development/module-setup/code-quality.md +++ b/for-developers/module-development/module-setup/code-quality.md @@ -5,21 +5,34 @@ sidebar_position: 4 description: Using prettier and a linter to prevent common bugs. --- -We recommend using [eslint](https://eslint.org/) and [prettier](https://prettier.io/) to improve the readability and uniformity of your code and to prevent easily-overlooked coding errors. The two tools work together to enforce the formatting and coding rules. If you are using an IDE such as VS Code, we recommend installing the prettier plugin. In that plugin you can also enable 'format on save' to automate some of the formatting. +We recommend using [eslint](https://eslint.org/) and +[prettier](https://prettier.io/) to improve the readability and uniformity of +your code and to prevent easily-overlooked coding errors. The two tools work +together to enforce the formatting and coding rules. If you are using an IDE +such as VS Code, we recommend installing the prettier plugin. In that plugin you +can also enable 'format on save' to automate some of the formatting. :::tip -Our [recommended templates](./file-structure.md) come with eslint and prettier configuration files. The remainder of this page is only necessary for people who are setting up their repo manually or want to upgrade an older module's repo... or if you just want to gain a deeper understanding of the mechanics of these config files. +Our [recommended templates](./file-structure.md) come with eslint and prettier +configuration files. The remainder of this page is only necessary for people who +are setting up their repo manually or want to upgrade an older module's repo... +or if you just want to gain a deeper understanding of the mechanics of these +config files. ::: ## Installation -If you are _not_ using the [recommended templates](./file-structure.md), you can configure your module for prettier and eslint as follows: +If you are _not_ using the [recommended templates](./file-structure.md), you can +configure your module for prettier and eslint as follows: -1. Run `yarn add --dev eslint prettier` in the root folder of your repo to install it as a dev dependency. -2. If you are using TypeScript you will also need to `yarn add --dev typescript-eslint`. -3. Add the line `"prettier": "@companion-module/tools/.prettierrc.json",` to your _package.json_ file. +1. Run `yarn add --dev eslint prettier` in the root folder of your repo to + install it as a dev dependency. +2. If you are using TypeScript you will also need to + `yarn add --dev typescript-eslint`. +3. Add the line `"prettier": "@companion-module/tools/.prettierrc.json",` to + your _package.json_ file. 4. Add the `scripts` block in your `package.json` to include: ```json @@ -37,7 +50,8 @@ package.json pkg ``` -You can list other files/folders here that should be ignored. We want to ignore package.json as prettier and yarn disagree on how it should be formatted. +You can list other files/folders here that should be ignored. We want to ignore +package.json as prettier and yarn disagree on how it should be formatted. ## ESLint config @@ -59,17 +73,23 @@ export default generateEslintConfig({ }) ``` -You can now run `yarn lint` and see any linter errors. If you need any help understanding the errors or warnings you are given, the eslint docs are really helpful. +You can now run `yarn lint` and see any linter errors. If you need any help +understanding the errors or warnings you are given, the eslint docs are really +helpful. :::note -If you have any suggestions on changes to make to this eslint config, do [open an issue](https://github.com/bitfocus/companion-module-tools/issues) to let us know. We hope that this set of rules will expand over time based on what is and isn't useful to module developers. +If you have any suggestions on changes to make to this eslint config, do +[open an issue](https://github.com/bitfocus/companion-module-tools/issues) to +let us know. We hope that this set of rules will expand over time based on what +is and isn't useful to module developers. ::: ### Enabling linting on commit -You can set it up so that git runs the linter when you make a commit, so you can be sure that only good code is committed. +You can set it up so that git runs the linter when you make a commit, so you can +be sure that only good code is committed. Install the needed tools `yarn add --dev lint-staged husky`. @@ -98,9 +118,11 @@ Run `yarn husky` to ensure husky is initialised. ### Running the linter on push -It is a good idea to setup a GitHub Actions workflow to run the linter, so that you don't get surprised by unexpected linter failures when running it locally. +It is a good idea to setup a GitHub Actions workflow to run the linter, so that +you don't get surprised by unexpected linter failures when running it locally. -To do this, create a new file in the repository at `.github/workflows/lint.yaml`, with the content: +To do this, create a new file in the repository at +`.github/workflows/lint.yaml`, with the content: ```yaml name: Lint @@ -172,10 +194,14 @@ export default customConfig ## Upgrading to @companion-module/tools v2.x -If you are upgrading your config from v1.x, you will need to reconfigure eslint, due to changes in both eslint and how the tools library provides config templates. +If you are upgrading your config from v1.x, you will need to reconfigure eslint, +due to changes in both eslint and how the tools library provides config +templates. -You can follow the steps for [ESLint Config](#eslint-config), with the following extra steps: +You can follow the steps for [ESLint Config](#eslint-config), with the following +extra steps: -Removing any existing `.eslintrc.json` or `.eslintrc.cjs`, you may want to port any custom configuration across to the new config file +Removing any existing `.eslintrc.json` or `.eslintrc.cjs`, you may want to port +any custom configuration across to the new config file That should be it! diff --git a/for-developers/module-development/module-setup/file-structure.md b/for-developers/module-development/module-setup/file-structure.md index 28cacdc..82a8733 100644 --- a/for-developers/module-development/module-setup/file-structure.md +++ b/for-developers/module-development/module-setup/file-structure.md @@ -5,24 +5,42 @@ sidebar_position: 1 description: Introduction to the file structure of a Companion module repository --- -When creating a new module, we strongly recommend using our **[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts)** as this will incorporate the latest module features and improvements. For those who prefer Javascript, we also have a [JavaScript template](https://github.com/bitfocus/companion-module-template). To get an idea of how a completed module looks, search for an existing module that may provide services similar to your equipment, or refer to reference modules such as [homeassistant-server](https://github.com/bitfocus/companion-module-homeassistant-server) (TypeScript) and [generic-osc](https://github.com/bitfocus/companion-module-generic-osc) (JavaScript). - -See the [setup instructions](../home#clone-or-copy-a-module-from-github) for more details on how to get started with the templates or another module. - -Below are the minimum files necessary to create a control module for Companion (aka Connection). You can add subfolders and other support files as needed. +When creating a new module, we strongly recommend using our +**[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts)** +as this will incorporate the latest module features and improvements. For those +who prefer Javascript, we also have a +[JavaScript template](https://github.com/bitfocus/companion-module-template). To +get an idea of how a completed module looks, search for an existing module that +may provide services similar to your equipment, or refer to reference modules +such as +[homeassistant-server](https://github.com/bitfocus/companion-module-homeassistant-server) +(TypeScript) and +[generic-osc](https://github.com/bitfocus/companion-module-generic-osc) +(JavaScript). + +See the [setup instructions](../home#clone-or-copy-a-module-from-github) for +more details on how to get started with the templates or another module. + +Below are the minimum files necessary to create a control module for Companion +(aka Connection). You can add subfolders and other support files as needed. :::tip -All of these files, and more, are included in the templates mentioned above. Using the templates will save you time in setting -things up and even more time by making sure the essential content has been included correctly -- especially for the package.json file! +All of these files, and more, are included in the templates mentioned above. +Using the templates will save you time in setting things up and even more time +by making sure the essential content has been included correctly -- especially +for the package.json file! -The templates also include sample source code to get you started programming the module's functionality. +The templates also include sample source code to get you started programming the +module's functionality. ::: ### File Structure -The essential repository structure includes the source code (in _src_ here), libraries that are automatically loaded by yarn (in _node_modules_) and a number of configuration files as follows: +The essential repository structure includes the source code (in _src_ here), +libraries that are automatically loaded by yarn (in _node_modules_) and a number +of configuration files as follows: ```text ├───companion @@ -45,73 +63,112 @@ The essential repository structure includes the source code (in _src_ here), lib ### companion/HELP.md -A structured 'Help' document that Companion users will see when clicking on the module help icon in the Connections page. +A structured 'Help' document that Companion users will see when clicking on the +module help icon in the Connections page. -Describe the module's capabilities and anything else they might need to know to use the module. +Describe the module's capabilities and anything else they might need to know to +use the module. -Format the contents using [markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax). +Format the contents using +[markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax). ### companion/manifest.json -Provides information to Companion about the module. See the [manifest.json](./manifest.json.md) page for full details. In particular, -be sure to name your module with the Companion convention: _companion-module-mymanufacturer-myproduct_ (replacing _mymanufacturer-myproduct_ with appropriate names). +Provides information to Companion about the module. See the +[manifest.json](./manifest.json.md) page for full details. In particular, be +sure to name your module with the Companion convention: +_companion-module-mymanufacturer-myproduct_ (replacing +_mymanufacturer-myproduct_ with appropriate names). ### node_modules folder -When you run `yarn install`, yarn reads the _package.json_ file and installs or updates all of the listed dependencies into the _node_modules_ folder. (It will create this folder if it doesn't already exist.) +When you run `yarn install`, yarn reads the _package.json_ file and installs or +updates all of the listed dependencies into the _node_modules_ folder. (It will +create this folder if it doesn't already exist.) -At a minimum, for Companion modules, it should install @companion-module/base and @companion-module/tools +At a minimum, for Companion modules, it should install @companion-module/base +and @companion-module/tools ### src/main.ts (or main.js, for the JavaScript template) -This main entrypoint for the module. The file and folder can be called something else, as long as the `"runtime": { "entrypoint": }` field in `companion/manifest.json` and the `"main":` field in `package.json` are updated to match. (Older JavaScript repos skip the subdirectory altogether, though this is no longer recommended.) +This main entrypoint for the module. The file and folder can be called something +else, as long as the `"runtime": { "entrypoint": }` field in +`companion/manifest.json` and the `"main":` field in `package.json` are updated +to match. (Older JavaScript repos skip the subdirectory altogether, though this +is no longer recommended.) -Generally you will create additional source-code files for each major module element: actions, feedback, presets, variables, user-configurations and upgrade scripts. (These files are already present in the template modules mentioned above.) +Generally you will create additional source-code files for each major module +element: actions, feedback, presets, variables, user-configurations and upgrade +scripts. (These files are already present in the template modules mentioned +above.) :::note -When TypeScript is "transpiled" into JavaScript, the code in `src/` is used to generate a `dist/` folder containing the corresponding JavaScript code. In a TypeScript repo, the manifest and package.json files therefore refer to the `dist/` folder even though your development code is in the `src/` folder. (But note that `dist/` is _not_ part of the git repository and must be listed in .gitignore file.) +When TypeScript is "transpiled" into JavaScript, the code in `src/` is used to +generate a `dist/` folder containing the corresponding JavaScript code. In a +TypeScript repo, the manifest and package.json files therefore refer to the +`dist/` folder even though your development code is in the `src/` folder. (But +note that `dist/` is _not_ part of the git repository and must be listed in +.gitignore file.) ::: ### .gitignore -This is a standard Git file that lists files and folders to be excluded from Git version control. `node_modules/` should always be included in the `.gitignore` as should `dist/` in TypeScript modules. +This is a standard Git file that lists files and folders to be excluded from Git +version control. `node_modules/` should always be included in the `.gitignore` +as should `dist/` in TypeScript modules. ### LICENSE -Companion is an MIT licensed project. We recommend modules released with the project are also MIT, and are open to other licenses being used if there is a good reason for it. +Companion is an MIT licensed project. We recommend modules released with the +project are also MIT, and are open to other licenses being used if there is a +good reason for it. -In the future it might be possible to use different licenses for modules, but that is not yet certain. +In the future it might be possible to use different licenses for modules, but +that is not yet certain. :::tip -Consult the Companion team if you wish to incorporate a dependency that does not have an MIT license. +Consult the Companion team if you wish to incorporate a dependency that does not +have an MIT license. ::: ### package.json -This is a standard node.js file to tell it about your project. It is required to be able to install dependencies to your module such as [@companion-module/base and @companion-module/tools](../module-lifecycle/companion-module-library.md). +This is a standard node.js file to tell it about your project. It is required to +be able to install dependencies to your module such as +[@companion-module/base and @companion-module/tools](../module-lifecycle/companion-module-library.md). ### README.md -This file should include any relevant developer documentation that the Companion Core and Module Development teams should be aware of, as well as any helpful information for people who wish to fork and contribute. It is only shown on github and when editing the module, so can be reasonably technical. +This file should include any relevant developer documentation that the Companion +Core and Module Development teams should be aware of, as well as any helpful +information for people who wish to fork and contribute. It is only shown on +github and when editing the module, so can be reasonably technical. As with the HELP.md file, you can format it with markdown. ### Additional files for good practices -In addition to the essential files we recommend several other files that help enforce good coding practices. -These files are all included in the templates recommended above and are discussed on separate pages of this section. +In addition to the essential files we recommend several other files that help +enforce good coding practices. These files are all included in the templates +recommended above and are discussed on separate pages of this section. -- [Code Quality Enforcement](./code-quality.md): prettier and eslint configuration -- [TypeScript configuration](./typescript-config.md) if you are using TypeScript (as recommended) +- [Code Quality Enforcement](./code-quality.md): prettier and eslint + configuration +- [TypeScript configuration](./typescript-config.md) if you are using TypeScript + (as recommended) - [Unit Testing Setup](./unit-testing.md) (there's not much there..) ## Next steps -- Set up your [_manifest.json_](./manifest.json.md) and _HELP.md_ files in the _companion/_ folder. +- Set up your [_manifest.json_](./manifest.json.md) and _HELP.md_ files in the + _companion/_ folder. - Look through the optional files mentioned above -- Familiarize yourself with the [Companion Module Library](../module-lifecycle/companion-module-library.md) concept -- Read through our introduction to module development: [Module Development 101](../module-development-101.md) +- Familiarize yourself with the + [Companion Module Library](../module-lifecycle/companion-module-library.md) + concept +- Read through our introduction to module development: + [Module Development 101](../module-development-101.md) diff --git a/for-developers/module-development/module-setup/index.md b/for-developers/module-development/module-setup/index.md index 2e0d24b..b743244 100644 --- a/for-developers/module-development/module-setup/index.md +++ b/for-developers/module-development/module-setup/index.md @@ -4,4 +4,5 @@ description: The files and file structure necessary to create a module repositor auto_toc: 3 --- -This section describes the files and file structure necessary to create a module repository. +This section describes the files and file structure necessary to create a module +repository. diff --git a/for-developers/module-development/module-setup/manifest.json.md b/for-developers/module-development/module-setup/manifest.json.md index 7bf498b..f1515bd 100644 --- a/for-developers/module-development/module-setup/manifest.json.md +++ b/for-developers/module-development/module-setup/manifest.json.md @@ -5,15 +5,22 @@ sidebar_position: 2 description: Specification of the Companion manifest file --- -Starting with Companion 3.0, Companion looks at the `companion/manifest.json` file for module information (before 3.0 it looked at `package.json`) This provides a companion specific and programming language agnostic manifest about your module. In the future this will allow us to do more powerful things! +Starting with Companion 3.0, Companion looks at the `companion/manifest.json` +file for module information (before 3.0 it looked at `package.json`) This +provides a companion specific and programming language agnostic manifest about +your module. In the future this will allow us to do more powerful things! -Read the [auto-generated documentation for manifest.json](https://bitfocus.github.io/companion-module-base/interfaces/ModuleManifest.html) for more details. +Read the +[auto-generated documentation for manifest.json](https://bitfocus.github.io/companion-module-base/interfaces/ModuleManifest.html) +for more details. -Tip: At any point you can validate your `manifest.json` by running `yarn companion-module-check`. +Tip: At any point you can validate your `manifest.json` by running +`yarn companion-module-check`. ## Format -If you are comfortable reading or working with JSON Schema, you can find the [formal definition in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/assets/manifest.schema.json) +If you are comfortable reading or working with JSON Schema, you can find the +[formal definition in the module-base repo](https://github.com/bitfocus/companion-module-base/blob/main/assets/manifest.schema.json) A full manifest definition is: @@ -48,24 +55,41 @@ A full manifest definition is: ## Properties -- `id` unique id of your module. This has to match the repository name excluding the `companion-module-` +- `id` unique id of your module. This has to match the repository name excluding + the `companion-module-` - `name` ??? - `shortname` ??? - `description` ??? - `manufacturer` ??? -- `products` An array of strings with the names of the products supported by your module. Often there is only a single product or sometimes the name of a series of products is better known than the products itself, then it is also good to give the series name. Your module will be listed with all associated product names. -- `keywords` Keywords to allow users to more easily find your module by searching, please do not repeat the manufacturer or product names here. -- `version` Version of your module. This should be left as `0.0.0`, the build process populates with the value in your `package.json` -- `license` License of your module code. This needs to be something MIT compatible to be allowed to be distributed with the official builds +- `products` An array of strings with the names of the products supported by + your module. Often there is only a single product or sometimes the name of a + series of products is better known than the products itself, then it is also + good to give the series name. Your module will be listed with all associated + product names. +- `keywords` Keywords to allow users to more easily find your module by + searching, please do not repeat the manufacturer or product names here. +- `version` Version of your module. This should be left as `0.0.0`, the build + process populates with the value in your `package.json` +- `license` License of your module code. This needs to be something MIT + compatible to be allowed to be distributed with the official builds - `repository` Git URL to the repository - `bugs` URL to the issue tracker. Users can follow this link to report bugs - `maintainers` List of maintainers of this module. -- `legacyIds` (Optional) List of old module ids. If the module has been renamed, the old names should be listed here to allow for seamless upgrading of old configs -- `runtime` This defines the runtime requirements of your module. Described more below +- `legacyIds` (Optional) List of old module ids. If the module has been renamed, + the old names should be listed here to allow for seamless upgrading of old + configs +- `runtime` This defines the runtime requirements of your module. Described more + below The runtime block is defined as: -- `type` This can be either `node18` or `node22`, depending on the required version of Node.js. In the future this may allow for other languages to be used. -- `api` This must be `nodejs-ipc`. It defines the protocol used between your module and Companion. In the future more options will be possible, to allow for other languages. -- `apiVersion` This should be left as `0.0.0`, the build process populates with the correct value -- `entrypoint` The main JavaScript file for your module. This is what companion will execute to start your module. +- `type` This can be either `node18` or `node22`, depending on the required + version of Node.js. In the future this may allow for other languages to be + used. +- `api` This must be `nodejs-ipc`. It defines the protocol used between your + module and Companion. In the future more options will be possible, to allow + for other languages. +- `apiVersion` This should be left as `0.0.0`, the build process populates with + the correct value +- `entrypoint` The main JavaScript file for your module. This is what companion + will execute to start your module. diff --git a/for-developers/module-development/module-setup/typescript-config.md b/for-developers/module-development/module-setup/typescript-config.md index ea5212f..1a65d95 100644 --- a/for-developers/module-development/module-setup/typescript-config.md +++ b/for-developers/module-development/module-setup/typescript-config.md @@ -7,12 +7,16 @@ description: Configuring the module to work with TypeScript. :::tip -This is an advanced topic. If you use the [recommended templates](./file-structure.md), a default typescript -config file is included and you will generally not want to change it. +This is an advanced topic. If you use the +[recommended templates](./file-structure.md), a default typescript config file +is included and you will generally not want to change it. ::: -The [recommended templates](./file-structure.md) provide typescript config presets in _tsconfig.json_ that we believe to be best practice, but they can be configured to be too strict for some, or may need to be modified if you change the name of the source or destination directories. +The [recommended templates](./file-structure.md) provide typescript config +presets in _tsconfig.json_ that we believe to be best practice, but they can be +configured to be too strict for some, or may need to be modified if you change +the name of the source or destination directories. A typical _tsconfig.json_ file looks like: @@ -63,6 +67,9 @@ Our TypeScript template splits it into two files: } ``` -You are free to override properties as you wish, this is only our recommendation after all. +You are free to override properties as you wish, this is only our recommendation +after all. -If you have any suggestions on changes to make to this base tsconfig, do [open an issue](https://github.com/bitfocus/companion-module-tools/issues) to let us know. We hope to collect some alternate presets along with recommended. +If you have any suggestions on changes to make to this base tsconfig, do +[open an issue](https://github.com/bitfocus/companion-module-tools/issues) to +let us know. We hope to collect some alternate presets along with recommended. diff --git a/for-developers/module-development/module-setup/unit-testing.md b/for-developers/module-development/module-setup/unit-testing.md index 1b07792..4ff4f20 100644 --- a/for-developers/module-development/module-setup/unit-testing.md +++ b/for-developers/module-development/module-setup/unit-testing.md @@ -5,11 +5,17 @@ sidebar_position: 6 description: Unit testing config and advice. --- -If you choose to include unit tests in your module repo, you can choose a framework such as Vitest, Mocha or Jest. [Vitest](https://vitest.dev/) may be especially useful for its native support of TypeScript. However, unit testing of modules is not very common: We find it quite hard to test most modules as to do so requires mocking-up the device connection. +If you choose to include unit tests in your module repo, you can choose a +framework such as Vitest, Mocha or Jest. [Vitest](https://vitest.dev/) may be +especially useful for its native support of TypeScript. However, unit testing of +modules is not very common: We find it quite hard to test most modules as to do +so requires mocking-up the device connection. -For TypeScript repos, you may need to add information to `compilerOptions": {"types": [] }`. +For TypeScript repos, you may need to add information to +`compilerOptions": {"types": [] }`. -If you have any suggestions on mocks, tooling or examples we should provide to make this easier, we are open to suggestions! +If you have any suggestions on mocks, tooling or examples we should provide to +make this easier, we are open to suggestions! Some modules which are known to have some unit tests: diff --git a/for-developers/setting-up-WSL.md b/for-developers/setting-up-WSL.md index 77d74bb..1ea086e 100644 --- a/for-developers/setting-up-WSL.md +++ b/for-developers/setting-up-WSL.md @@ -5,41 +5,73 @@ sidebar_position: 1.1 description: How to set up Windows System for Linux (WSL) for Companion development --- -For other platforms see: [Initial Setup](setting-up-developer-environment.md) instead. +For other platforms see: [Initial Setup](setting-up-developer-environment.md) +instead. ## Install WSL -Although it is possible to develop directly in Windows, there are occasions when you might want to use a Linux environment under Windows. The key is to use Windows' Subsystem for Linux (WSL). +Although it is possible to develop directly in Windows, there are occasions when +you might want to use a Linux environment under Windows. The key is to use +Windows' Subsystem for Linux (WSL). -First install Windows Subsystem for Linux version 2 (WSL2), -WSL is included with Windows but needs to be activated. Follow [Microsoft’s installation instructions](https://learn.microsoft.com/en-us/windows/wsl/setup/environment). Basically, open a command or powershell window and type: +First install Windows Subsystem for Linux version 2 (WSL2), WSL is included with +Windows but needs to be activated. Follow +[Microsoft’s installation instructions](https://learn.microsoft.com/en-us/windows/wsl/setup/environment). +Basically, open a command or powershell window and type: ```powershell wsl --install ``` -After this completes, reboot your computer and WSL will automatically install the latest LTS version of Ubuntu. (24.04 at this time of writing). +After this completes, reboot your computer and WSL will automatically install +the latest LTS version of Ubuntu. (24.04 at this time of writing). ## Install the basic development tools Once this is done continue through Microsoft’s instructions, especially - `sudo apt update && sudo apt upgrade`, -as well as the instructions to: +`sudo apt update && sudo apt upgrade`, as well as the instructions to: - Set up Windows terminal, - Set up VS Code, and - Set up Git. -If you develop with Visual Studio Code, which we currently recommend, then you can do remote developing. That means VS Code runs on Windows but it opens a connection to the WSL virtual machine. It allows you to edit the files in the WSL file system. VS Code also has an integrated terminal so you can work on the WSL OS (typically Ubuntu). For that you should install the [WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) extension and follow [Microsoft’s instructions here](https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode). You will see the connection info on the bottom left of each window and you can connect there or by the command palette. You can debug using breakpoints etc. either by starting automatic debugging from the terminal or by attaching to the running Node.js process (though it may be hard to find: it should be the first one in the list when you type ctrl-shift-P and “Debug: Attach to Node Process” but isn't always so). - -You will need to install all the prerequisite tools on the WSL machine just like you would do on Linux, as described in the [Setting Up A Developer Environment](setting-up-developer-environment.md). - -When you are running Companion from a VS Code terminal, VS Code will know the network ports and create automatic port forwards for you. That means although Companion runs on the virtual machine, you'll be able to access the admin page from your Windows host by accessing localhost or 127.0.0.1 and the used port. -That makes it quite convenient but you always have to remember that Companion runs on a virtual machine inside of your computer and that virtual machine has a different IP-address. When you want to access the API of software running on your Windows host, you can't use 127.0.0.1 like you would without WSL. 127.0.0.1 is the localhost of the WSL. WSL sets up a virtual network interface for you and to access your host OS, you have to use 172.28.96.1. Verify this using the command `ip route` in your Linux shell. +If you develop with Visual Studio Code, which we currently recommend, then you +can do remote developing. That means VS Code runs on Windows but it opens a +connection to the WSL virtual machine. It allows you to edit the files in the +WSL file system. VS Code also has an integrated terminal so you can work on the +WSL OS (typically Ubuntu). For that you should install the +[WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) +extension and follow +[Microsoft’s instructions here](https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode). +You will see the connection info on the bottom left of each window and you can +connect there or by the command palette. You can debug using breakpoints etc. +either by starting automatic debugging from the terminal or by attaching to the +running Node.js process (though it may be hard to find: it should be the first +one in the list when you type ctrl-shift-P and “Debug: Attach to Node Process” +but isn't always so). + +You will need to install all the prerequisite tools on the WSL machine just like +you would do on Linux, as described in the +[Setting Up A Developer Environment](setting-up-developer-environment.md). + +When you are running Companion from a VS Code terminal, VS Code will know the +network ports and create automatic port forwards for you. That means although +Companion runs on the virtual machine, you'll be able to access the admin page +from your Windows host by accessing localhost or 127.0.0.1 and the used port. +That makes it quite convenient but you always have to remember that Companion +runs on a virtual machine inside of your computer and that virtual machine has a +different IP-address. When you want to access the API of software running on +your Windows host, you can't use 127.0.0.1 like you would without WSL. 127.0.0.1 +is the localhost of the WSL. WSL sets up a virtual network interface for you and +to access your host OS, you have to use 172.28.96.1. Verify this using the +command `ip route` in your Linux shell. ## Set Up Access to USB Ports -If you want to use USB-devices in WSL, it gets complicated because WSL doesn't have built-in USB passthrough features. The solution is USB over IP software. That means you capture the USB packets at the host, transmit it to the virtual machine and then inject it to the USB system there. Here is how it's done: +If you want to use USB-devices in WSL, it gets complicated because WSL doesn't +have built-in USB passthrough features. The solution is USB over IP software. +That means you capture the USB packets at the host, transmit it to the virtual +machine and then inject it to the USB system there. Here is how it's done: You may have to run the following in a Linux shell: @@ -50,9 +82,12 @@ apt-get install -y libusb-1.0-0-dev libudev-dev libfontconfig1 Then: -- On Windows install the [USB-IP driver](https://github.com/dorssel/usbipd-win/releases) -- Optional but highly recommended install a GUI to control the USB connections: [WSL USB Manager](https://gitlab.com/alelec/wsl-usb-gui/-/releases) -- Make sure your WSL kernel is at least version 5.15.150.1 (released Mar 2024) (`uname -a`). If not, update your kernel. +- On Windows install the + [USB-IP driver](https://github.com/dorssel/usbipd-win/releases) +- Optional but highly recommended install a GUI to control the USB connections: + [WSL USB Manager](https://gitlab.com/alelec/wsl-usb-gui/-/releases) +- Make sure your WSL kernel is at least version 5.15.150.1 (released Mar 2024) + (`uname -a`). If not, update your kernel. - Linux distributions need extra rules to make USB devices accessible to users: - Copy the following code into a bash shell (terminal) to create the rules file: @@ -63,11 +98,23 @@ EOF ``` -- Now reboot the Computer (It may be sufficient to type: `sudo udevadm control --reload-rules`.) +- Now reboot the Computer (It may be sufficient to type: + `sudo udevadm control --reload-rules`.) - Open the WSL USB Manager in Windows -- Attach your USB device. You should see it popping up in the top pane of the manager. -- Check the "bound" checkbox next to your USB device (usbip will now remember this permission; you won't have to do it again.) -- Select the USB device by clicking on it and then press the "Attach" button. The device should now move from the top pane to the forwarded devices pane. -- Optional: on the linux shell use `lsusb` to check if you find your device and remember the bus and device number. -- Optional: In the linux shell use `cat /dev/bus/usb/001/003` to check if you have access to the device. Replace the numbers (/001/003) with the bus number and the device number that you have found with lsusb -- _Note: most Companion's USB surfaces are handled as HID devices. WSL presents the HID interface through a separate “device” than shown by_ `lsusb` _Instead when an HID device is added via the usb-ip driver, it will set up_ `/dev/hidraw#` where # is an integer starting from 1. If permissions are incorrectly set, Companion will output an error message in the terminal. _You can also test it directly, as above._ +- Attach your USB device. You should see it popping up in the top pane of the + manager. +- Check the "bound" checkbox next to your USB device (usbip will now remember + this permission; you won't have to do it again.) +- Select the USB device by clicking on it and then press the "Attach" button. + The device should now move from the top pane to the forwarded devices pane. +- Optional: on the linux shell use `lsusb` to check if you find your device and + remember the bus and device number. +- Optional: In the linux shell use `cat /dev/bus/usb/001/003` to check if you + have access to the device. Replace the numbers (/001/003) with the bus number + and the device number that you have found with lsusb +- _Note: most Companion's USB surfaces are handled as HID devices. WSL presents + the HID interface through a separate “device” than shown by_ `lsusb` _Instead + when an HID device is added via the usb-ip driver, it will set up_ + `/dev/hidraw#` where # is an integer starting from 1. If permissions are + incorrectly set, Companion will output an error message in the terminal. _You + can also test it directly, as above._ diff --git a/for-developers/setting-up-developer-environment.md b/for-developers/setting-up-developer-environment.md index 4d17bec..8499700 100644 --- a/for-developers/setting-up-developer-environment.md +++ b/for-developers/setting-up-developer-environment.md @@ -5,38 +5,57 @@ sidebar_position: 1 description: Setting up a Developer Environment --- -import UserGuideLink from '@site/src/UserGuideLink'; +import UserGuideLink from '@site/src/UserGuideLink' -Companion is written in Javascript/TypeScript and uses the [Node.js](https://nodejs.org/en/) runtime. In addition, all parts of Companion are organized and tracked using [Git](./git-workflows/installing-git.md). Here we will provide instructions for installing the development tools you will need for contributing to Companion, whether as a module or a part of core Companion. +Companion is written in Javascript/TypeScript and uses the +[Node.js](https://nodejs.org/en/) runtime. In addition, all parts of Companion +are organized and tracked using [Git](./git-workflows/installing-git.md). Here +we will provide instructions for installing the development tools you will need +for contributing to Companion, whether as a module or a part of core Companion. -Companion, Javascript and Node.js are platform independent, so you can develop on Windows, macOS or Linux and the code you write will be able to run on all three platforms. +Companion, Javascript and Node.js are platform independent, so you can develop +on Windows, macOS or Linux and the code you write will be able to run on all +three platforms. :::note -For module development you may be able to skip step 5, below, "Enabling USB on Unix". Instead -simply install Companion according to the instructions in the getting started guide. +For module development you may be able to skip step 5, below, "Enabling USB on +Unix". Instead simply install Companion according to the instructions in the +getting started guide. ::: ## 1. Install Node.js manager (fnm) -We strongly recommend using the [fnm](https://github.com/Schniz/fnm#installation) version manager to allow for easily updating and switching between Node.js versions. If you choose to install Node.js without fnm, you will still need to ensure you a running the right Node.js versions as Companion evolves. +We strongly recommend using the +[fnm](https://github.com/Schniz/fnm#installation) version manager to allow for +easily updating and switching between Node.js versions. If you choose to install +Node.js without fnm, you will still need to ensure you a running the right +Node.js versions as Companion evolves. ### Installing fnm on Windows :::note -If you want to run in Linux Subsystem for Windows (aka WSL), please follow the [WSL Instructions page](setting-up-WSL.md) and then follow the instructions, below, in the [Linux section, below](#installing-fnm-on-linux-and-macos). +If you want to run in Linux Subsystem for Windows (aka WSL), please follow the +[WSL Instructions page](setting-up-WSL.md) and then follow the instructions, +below, in the [Linux section, below](#installing-fnm-on-linux-and-macos). ::: :::tip -If PowerShell complains about unsigned apps, go to Settings, search for "developer settings" and enable "Change execution policy to allow local PowerShell scripts to run without signing". Alternatively, in a PowerShell with elevated permissions run: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` +If PowerShell complains about unsigned apps, go to Settings, search for +"developer settings" and enable "Change execution policy to allow local +PowerShell scripts to run without signing". Alternatively, in a PowerShell with +elevated permissions run: +`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` ::: -If you are new to code development on Windows, the built-in `winget` command is probably the simplest way to install fnm. (Other popular package managers such as Chocolatey and Scoop work similarly.) +If you are new to code development on Windows, the built-in `winget` command is +probably the simplest way to install fnm. (Other popular package managers such +as Chocolatey and Scoop work similarly.) In Powershell (admin mode) type: @@ -44,7 +63,9 @@ In Powershell (admin mode) type: winget install Schniz.fnm ``` -Once it has loaded, configure PowerShell as described in the fnm GitHub repo. Briefly you need to add a line to the end of the powershell startup script (aka profile). The following opens the profile file in a text editor +Once it has loaded, configure PowerShell as described in the fnm GitHub repo. +Briefly you need to add a line to the end of the powershell startup script (aka +profile). The following opens the profile file in a text editor ```powershell if (-not (Test-Path $profile)) { New-Item $profile -Force } @@ -59,7 +80,8 @@ fnm env --use-on-cd --corepack-enabled --version-file-strategy=recursive --shell ### Installing fnm on Linux and MacOS -Use the following script (see [fnm instructions in GitHub](https://github.com/Schniz/fnm?tab=readme-ov-file#installation)) +Use the following script (see +[fnm instructions in GitHub](https://github.com/Schniz/fnm?tab=readme-ov-file#installation)) ```bash curl -fsSL https://fnm.vercel.app/install | bash @@ -67,7 +89,8 @@ curl -fsSL https://fnm.vercel.app/install | bash :::note -The install script requires unzip to be installed on your system. If it isn't, install it by typing: +The install script requires unzip to be installed on your system. If it isn't, +install it by typing: ``` sudo apt install unzip @@ -77,7 +100,8 @@ sudo apt install unzip **upgrading fnm**: -on MacOS upgrade fnm using Homebrew: `brew upgrade fnm` (you can also install using manually using Homebrew) +on MacOS upgrade fnm using Homebrew: `brew upgrade fnm` (you can also install +using manually using Homebrew) on other Linux systems upgrade using: @@ -87,8 +111,9 @@ curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell ## 2. Install Node.js using fnm -Once you have installed fnm, execute the following in a terminal/PowerShell. -To install Node.js v22 (the version required for Core Companion development at the time of writing) and make it the default. +Once you have installed fnm, execute the following in a terminal/PowerShell. To +install Node.js v22 (the version required for Core Companion development at the +time of writing) and make it the default. ```bash fnm install 22 @@ -97,33 +122,47 @@ fnm default 22 corepack enable ``` -(Note: `corepack enable` may not be needed in Windows if using PowerShell with the setup described above.) +(Note: `corepack enable` may not be needed in Windows if using PowerShell with +the setup described above.) :::note -Some older modules uses node v18 instead of v22, but are encouraged to update to v22. Sometimes updating the node version can introduce new bugs, but staying on older versions makes development harder as tools drop support for those versions. At some point, Companion will require modules to be node v22 (or perhaps a newer version). +Some older modules uses node v18 instead of v22, but are encouraged to update to +v22. Sometimes updating the node version can introduce new bugs, but staying on +older versions makes development harder as tools drop support for those +versions. At some point, Companion will require modules to be node v22 (or +perhaps a newer version). -With fnm you can install both v18 and v22 and quickly switch between versions as needed. fnm can be setup to do this automatically with the `--use-on-cd` switch (as recommended in the [Windows section](#installing-fnm-on-windows) above), or you can switch it manually with a command like `fnm use 22`. See the [fnm config](https://github.com/Schniz/fnm/blob/master/docs/configuration.md) docs for more information on `--use-on-cd` and the related `--resolve-engines` options. +With fnm you can install both v18 and v22 and quickly switch between versions as +needed. fnm can be setup to do this automatically with the `--use-on-cd` switch +(as recommended in the [Windows section](#installing-fnm-on-windows) above), or +you can switch it manually with a command like `fnm use 22`. See the +[fnm config](https://github.com/Schniz/fnm/blob/master/docs/configuration.md) +docs for more information on `--use-on-cd` and the related `--resolve-engines` +options. ::: :::warning -Do not install yarn directly. Instead, let corepack ensure that the right version is installed -when you run `yarn install`. If you have already installed +Do not install yarn directly. Instead, let corepack ensure that the right +version is installed when you run `yarn install`. If you have already installed yarn globally and are having problems, consider removing the global install. ::: ## 3. Install and setup git -See the [instructions for installing Git here](./git-workflows/installing-git.md). +See the +[instructions for installing Git here](./git-workflows/installing-git.md). :::info[Windows Note] As per [the windows note here](./git-workflows/installing-git.md#configure-git): -In order for `git clone` to give you `lf` endings, this default needs to be overridden _**before you clone the companion repository**_. In a git bash window type: +In order for `git clone` to give you `lf` endings, this default needs to be +overridden _**before you clone the companion repository**_. In a git bash window +type: ```bash git config set --global core.autocrlf false @@ -134,24 +173,30 @@ git config set --global core.eol lf ## 4. Enabling USB access on Linux Systems -If you are using linux, you should follow the dependencies and udev rules steps as described in the README included in the release builds https://github.com/bitfocus/companion/tree/main/assets/linux. +If you are using linux, you should follow the dependencies and udev rules steps +as described in the README included in the release builds +https://github.com/bitfocus/companion/tree/main/assets/linux. For WSL, follow the [WSL setup instructions](setting-up-WSL.md) instead. ## 5. Editing Code / Integrated Development Environment (IDE) -To edit the source code or write new code you can use any text editor you like, but there are many editors which are made especially for developing computer code or even better especially for JavaScript. -If you have no prior experience, we recommend the [Visual Studio Code](https://code.visualstudio.com/) editor (VS Code). +To edit the source code or write new code you can use any text editor you like, +but there are many editors which are made especially for developing computer +code or even better especially for JavaScript. If you have no prior experience, +we recommend the [Visual Studio Code](https://code.visualstudio.com/) editor (VS +Code). :::tip -We recommend installing the _ESLint_, _prettier_ and _typos_ plugins for VS Code. +We recommend installing the _ESLint_, _prettier_ and _typos_ plugins for VS +Code. ::: :::note[Linux Note] -If you want a simple windowing text-editor in Linux, you can try gedit. Install it with `sudo apt install gedit` +If you want a simple windowing text-editor in Linux, you can try gedit. Install +it with `sudo apt install gedit` ::: - From 1e4db86bf55fd108d6cab452122b222f214249fc Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 21:54:32 -0800 Subject: [PATCH 05/12] fix: replace all generic image tags Bonus: (not directly needed for this PR) - Replace `![image]()` with a descriptive label. --- for-developers/core-development/build-companion.md | 4 ++-- for-developers/git-workflows/github-workflow.md | 2 +- .../connection-advanced/bonjour-device-discovery.md | 3 ++- for-developers/module-development/local-modules.md | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/for-developers/core-development/build-companion.md b/for-developers/core-development/build-companion.md index eb05d2c..cf3a1f8 100644 --- a/for-developers/core-development/build-companion.md +++ b/for-developers/core-development/build-companion.md @@ -66,13 +66,13 @@ allow building Companion in Windows: 2. Turn on Developer Mode in Windows Settings. (Open Settings and search for "developer"): - ![image](images/developers-setting.png) + ![Windows Developer Settings](images/developers-setting.png) 3. Set a local policy in the “Local Security Policy” editor: Security Settings > Local Policies > User Rights Assignment: Create symbolic links, to allow yourself to create symlinks: - ![image](images/set-symlink-permission.png) + ![Windows Symlink Permissions](images/set-symlink-permission.png) ::: diff --git a/for-developers/git-workflows/github-workflow.md b/for-developers/git-workflows/github-workflow.md index defe12c..c8ebd56 100644 --- a/for-developers/git-workflows/github-workflow.md +++ b/for-developers/git-workflows/github-workflow.md @@ -5,7 +5,7 @@ sidebar_position: 3 description: Introduction to git and github workflow for beginners --- -![image](images/github-contribution-workflow.png) +![Github Contribution Workflow Diagram](images/github-contribution-workflow.png) The following is the basic workflow for contributing to Companion (and many other open-source repositories) on GitHub. The order of operations is a key to diff --git a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md index ce5df16..24bd112 100644 --- a/for-developers/module-development/connection-advanced/bonjour-device-discovery.md +++ b/for-developers/module-development/connection-advanced/bonjour-device-discovery.md @@ -41,7 +41,8 @@ and in your `companion/manifest.json`: These two structures are linked by the common id, in the future this will allow us to automate device discovery further. -In the UI, this field will look like: ![image](../images/bonjour.png) +In the UI, this field will look like: +![Bonjour Host Dropdown](../images/bonjour.png) The 'Manual' option is always shown, and must be handled to allow users to manually specify an address for environments where Bonjour does not work. This diff --git a/for-developers/module-development/local-modules.md b/for-developers/module-development/local-modules.md index 7f1e7d0..06e3e00 100644 --- a/for-developers/module-development/local-modules.md +++ b/for-developers/module-development/local-modules.md @@ -29,12 +29,12 @@ corresponding to a different module. - Check the section above on how to structure this folder - Open/show the launcher window of Companion: - ![image](images/launcher.png) + ![Companion Launcher](images/launcher.png) - In the top right corner you will see a Cog. Click on it to show the **Advanced Settings** window: -![image](images/launcher-advanced.png) +![Launcher Advanced Settings Window](images/launcher-advanced.png) - In the **Developer** section click on _**Select**_ to specify the directory where you have stored your developer modules. From c1a0b37bb11ee2308b5b349c50fcc213a34e27f7 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 21:11:39 -0800 Subject: [PATCH 06/12] feat: center markdown images by default This improves readability and simplifies some cases. (A complete search of the repo did not reveal any cases in which this breaks the current text-flow, i.e. by breaking up a single line.) Note a nice side-effect is that the image will always appear on its own line. (If you need to override this, it should be possible with inline html/style.) Note: this is prelude to an internal reformat of for-developers (i.e. reformat the files with essentially no change to the built website) --- src/css/custom.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/css/custom.css b/src/css/custom.css index ef8c1a7..e972fd5 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -293,3 +293,9 @@ .markdown h3 { font-size: 1.25em; } + +.markdown img { + display: block; + margin-left: auto; + margin-right: auto; +} From d7578bf4ac039006579dda0f0eedd05f40cdd369 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 22:57:19 -0800 Subject: [PATCH 07/12] fix main rabbit issues and rerun format --- .prettierrc | 2 +- for-developers/git-workflows/github-workflow.md | 8 +++++--- .../module-development/api-changes/v2.0.md | 3 ++- .../module-development/module-lifecycle/index.md | 3 ++- .../module-lifecycle/releasing-your-module.md | 3 ++- ...g-a-custom-version-of-@companion-module-base.md | 3 ++- .../module-development/module-setup/index.md | 3 ++- .../module-setup/typescript-config.md | 14 ++++++++++++-- .../module-setup/unit-testing.md | 2 +- for-developers/setting-up-WSL.md | 3 ++- for-developers/setting-up-developer-environment.md | 3 ++- src/css/custom.css | 2 +- 12 files changed, 34 insertions(+), 15 deletions(-) diff --git a/.prettierrc b/.prettierrc index d30dcc5..739f9a7 100644 --- a/.prettierrc +++ b/.prettierrc @@ -23,7 +23,7 @@ } }, { - "files": "for-developers/**/*.md, for-developers/**/*.mdx", + "files": ["for-developers/**/*.md", "for-developers/**/*.mdx"], "options": { "proseWrap": "always", "printWidth": 80, diff --git a/for-developers/git-workflows/github-workflow.md b/for-developers/git-workflows/github-workflow.md index c8ebd56..60c4217 100644 --- a/for-developers/git-workflows/github-workflow.md +++ b/for-developers/git-workflows/github-workflow.md @@ -5,7 +5,7 @@ sidebar_position: 3 description: Introduction to git and github workflow for beginners --- -![Github Contribution Workflow Diagram](images/github-contribution-workflow.png) +![image](images/github-contribution-workflow.png) The following is the basic workflow for contributing to Companion (and many other open-source repositories) on GitHub. The order of operations is a key to @@ -29,7 +29,9 @@ bitfocus/companion-module-generic-http.) you're contributing to an existing repository. Eventually you may get write-access, for example if you become the maintainer of a Companion module, in which case the flow can be simplified...but it's still good practice to - develop new features on a new branch. ::: + develop new features on a new branch. + +::: :::note[Expert Note] @@ -89,7 +91,7 @@ On the GitHub page for your new fork, copy the HTTPS link to your fork using the green **<> Code ▼** button. Then paste it on a line starting with -`it remote add personal`. It should look like this (for core Companion): +`git remote add personal`. It should look like this (for core Companion): ```bash git remote add personal https://github.com//companion.git diff --git a/for-developers/module-development/api-changes/v2.0.md b/for-developers/module-development/api-changes/v2.0.md index 357bed7..69c6dad 100644 --- a/for-developers/module-development/api-changes/v2.0.md +++ b/for-developers/module-development/api-changes/v2.0.md @@ -1,7 +1,8 @@ --- title: API 2.0 (Companion 4.3+) sidebar_position: -200 -description: 'Overview of API 2.0 breaking changes (expression parsing, presets overhaul, +description: + 'Overview of API 2.0 breaking changes (expression parsing, presets overhaul, TypeScript improvements).' --- diff --git a/for-developers/module-development/module-lifecycle/index.md b/for-developers/module-development/module-lifecycle/index.md index 8c03bae..67ca583 100644 --- a/for-developers/module-development/module-lifecycle/index.md +++ b/for-developers/module-development/module-lifecycle/index.md @@ -1,6 +1,7 @@ --- title: 'Module Development Lifecycle: Release and Maintenance' -description: The task necessary to release, maintain and upgrade a module repository over +description: + The task necessary to release, maintain and upgrade a module repository over time. auto_toc: 2 --- diff --git a/for-developers/module-development/module-lifecycle/releasing-your-module.md b/for-developers/module-development/module-lifecycle/releasing-your-module.md index a2de0d1..3106b6f 100644 --- a/for-developers/module-development/module-lifecycle/releasing-your-module.md +++ b/for-developers/module-development/module-lifecycle/releasing-your-module.md @@ -2,7 +2,8 @@ title: 'Releasing a Companion Module' sidebar_label: 'Release a module' sidebar_position: 3 -description: How to release your module for delivery to others using Companion's "web +description: + How to release your module for delivery to others using Companion's "web store". --- diff --git a/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md b/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md index 7fd4b1b..0e2257e 100644 --- a/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md +++ b/for-developers/module-development/module-lifecycle/testing-a-custom-version-of-@companion-module-base.md @@ -2,7 +2,8 @@ title: 'Using a custom @companion-module/base library' sidebar_label: 'Custom @companion-module/base' sidebar_position: 8 -description: How to test and use your module with a non-release version of the companion +description: + How to test and use your module with a non-release version of the companion modules. --- diff --git a/for-developers/module-development/module-setup/index.md b/for-developers/module-development/module-setup/index.md index b743244..453d3f2 100644 --- a/for-developers/module-development/module-setup/index.md +++ b/for-developers/module-development/module-setup/index.md @@ -1,6 +1,7 @@ --- title: Module Setup and Structure -description: The files and file structure necessary to create a module repository. +description: + The files and file structure necessary to create a module repository. auto_toc: 3 --- diff --git a/for-developers/module-development/module-setup/typescript-config.md b/for-developers/module-development/module-setup/typescript-config.md index 1a65d95..3683ad8 100644 --- a/for-developers/module-development/module-setup/typescript-config.md +++ b/for-developers/module-development/module-setup/typescript-config.md @@ -24,7 +24,12 @@ A typical _tsconfig.json_ file looks like: { "extends": "@companion-module/tools/tsconfig/node22/recommended", "include": ["src/**/*.ts"], - "exclude": ["node_modules/**", "src/**/*spec.ts", "src/**/__tests__/*", "src/**/__mocks__/*"], + "exclude": [ + "node_modules/**", + "src/**/*spec.ts", + "src/**/__tests__/*", + "src/**/__mocks__/*", + ], "compilerOptions": { "outDir": "./dist", "baseUrl": "./", @@ -54,7 +59,12 @@ Our TypeScript template splits it into two files: { "extends": "@companion-module/tools/tsconfig/node22/recommended", "include": ["src/**/*.ts"], - "exclude": ["node_modules/**", "src/**/*spec.ts", "src/**/__tests__/*", "src/**/__mocks__/*"], + "exclude": [ + "node_modules/**", + "src/**/*spec.ts", + "src/**/__tests__/*", + "src/**/__mocks__/*", + ], "compilerOptions": { "outDir": "./dist", "baseUrl": "./", diff --git a/for-developers/module-development/module-setup/unit-testing.md b/for-developers/module-development/module-setup/unit-testing.md index 4ff4f20..8ab676d 100644 --- a/for-developers/module-development/module-setup/unit-testing.md +++ b/for-developers/module-development/module-setup/unit-testing.md @@ -12,7 +12,7 @@ modules is not very common: We find it quite hard to test most modules as to do so requires mocking-up the device connection. For TypeScript repos, you may need to add information to -`compilerOptions": {"types": [] }`. +`"compilerOptions": {"types": [] }`. If you have any suggestions on mocks, tooling or examples we should provide to make this easier, we are open to suggestions! diff --git a/for-developers/setting-up-WSL.md b/for-developers/setting-up-WSL.md index 1ea086e..8052452 100644 --- a/for-developers/setting-up-WSL.md +++ b/for-developers/setting-up-WSL.md @@ -2,7 +2,8 @@ title: Setting Up WSL for the Developer Environment sidebar_label: '└─ WSL Setup Notes' sidebar_position: 1.1 -description: How to set up Windows System for Linux (WSL) for Companion development +description: + How to set up Windows System for Linux (WSL) for Companion development --- For other platforms see: [Initial Setup](setting-up-developer-environment.md) diff --git a/for-developers/setting-up-developer-environment.md b/for-developers/setting-up-developer-environment.md index 8499700..8cdf2a1 100644 --- a/for-developers/setting-up-developer-environment.md +++ b/for-developers/setting-up-developer-environment.md @@ -21,7 +21,8 @@ three platforms. For module development you may be able to skip step 5, below, "Enabling USB on Unix". Instead simply install Companion according to the instructions in the -getting started guide. +getting started +guide. ::: diff --git a/src/css/custom.css b/src/css/custom.css index e972fd5..d8b7cca 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -294,7 +294,7 @@ font-size: 1.25em; } -.markdown img { +.markdown p > img:last-child { display: block; margin-left: auto; margin-right: auto; From 64e36936c731cd2766859ac182bf0f288769f6b5 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Sat, 28 Feb 2026 23:57:27 -0800 Subject: [PATCH 08/12] fix improve css selector (sync with PR #40) Using p > img (suggested in PR #42) leads to too many edge-cases that fail. For example, if the image is clickable, i.e. inside ``. The following is more robust and still overrideable by adding an element after it (such as ). --- src/css/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/custom.css b/src/css/custom.css index d8b7cca..f9f46bf 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -294,7 +294,7 @@ font-size: 1.25em; } -.markdown p > img:last-child { +.markdown img:last-child { display: block; margin-left: auto; margin-right: auto; From a92b5ed80510ff81c4bb09a22cc9cd06a595e58a Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Mon, 2 Mar 2026 15:48:23 -0800 Subject: [PATCH 09/12] fix reflow merged files --- .../module-development/api-changes/v2.0.md | 3 ++- .../connection-basics/variables.md | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/for-developers/module-development/api-changes/v2.0.md b/for-developers/module-development/api-changes/v2.0.md index e8c8a31..cc1b4b3 100644 --- a/for-developers/module-development/api-changes/v2.0.md +++ b/for-developers/module-development/api-changes/v2.0.md @@ -106,7 +106,8 @@ have missed. ### Updates to `setVariableDefinitions` -To better match the other similar methods, `setVariableDefinitions` no longer expects an array of definitions, and instead expects an object +To better match the other similar methods, `setVariableDefinitions` no longer +expects an array of definitions, and instead expects an object Before: diff --git a/for-developers/module-development/connection-basics/variables.md b/for-developers/module-development/connection-basics/variables.md index 789283e..c507e13 100644 --- a/for-developers/module-development/connection-basics/variables.md +++ b/for-developers/module-development/connection-basics/variables.md @@ -37,11 +37,17 @@ defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the variable definitions into even more files/folders. -The [TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) includes a file `src/variables.ts`, which is where your variables should be defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the variable definitions into even more files/folders. +The +[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) +includes a file `src/variables.ts`, which is where your variables should be +defined. It is not required to use this structure, but it keeps it more readable +than having everything in one file. More complex modules will likely want to +split the variable definitions into even more files/folders. ### API 2.x -All the variable definitions are passed in as a single JavaScript object, in the form of: +All the variable definitions are passed in as a single JavaScript object, in the +form of: ```js const definitions = { @@ -59,7 +65,8 @@ VariableId must only use letters [a-zA-Z], numbers, underscore, hyphen. ### API 1.x -All the variable definitions are passed in as a single JavaScript array, in the form of: +All the variable definitions are passed in as a single JavaScript array, in the +form of: ```js const definitions = [ From 2764970a4a8b630ec7abdd25d7c7fcbd6b38a64f Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Mon, 2 Mar 2026 16:55:24 -0800 Subject: [PATCH 10/12] minor copy-edits after comparing this PR with main Visually, all rendered pages are structurally identical in the browser. Exceptions are mainly due to intentionally removing incorrect line breaks or very minor copy-edits. --- .../module-development/connection-basics/variables.md | 7 ------- for-developers/module-development/local-modules.md | 4 ++-- .../module-lifecycle/renaming-your-module.md | 2 +- .../module-development/module-setup/typescript-config.md | 4 ++-- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/for-developers/module-development/connection-basics/variables.md b/for-developers/module-development/connection-basics/variables.md index c507e13..34b63cd 100644 --- a/for-developers/module-development/connection-basics/variables.md +++ b/for-developers/module-development/connection-basics/variables.md @@ -37,13 +37,6 @@ defined. It is not required to use this structure, but it keeps it more readable than having everything in one file. More complex modules will likely want to split the variable definitions into even more files/folders. -The -[TypeScript module template](https://github.com/bitfocus/companion-module-template-ts) -includes a file `src/variables.ts`, which is where your variables should be -defined. It is not required to use this structure, but it keeps it more readable -than having everything in one file. More complex modules will likely want to -split the variable definitions into even more files/folders. - ### API 2.x All the variable definitions are passed in as a single JavaScript object, in the diff --git a/for-developers/module-development/local-modules.md b/for-developers/module-development/local-modules.md index 06e3e00..54534f2 100644 --- a/for-developers/module-development/local-modules.md +++ b/for-developers/module-development/local-modules.md @@ -16,10 +16,10 @@ module folder is specified as described below. Inside of this folder should be one or more folders that use the following layouts, with each folder corresponding to a different module. -1. A git clone of a module from github This requires some additional setup, as +1. **A git clone of a module from github**. This requires some additional setup, as the module will need to be prepared with a `yarn install`, and for some, a `yarn build`. -2. Packaged output This is a folder that contains a `companion/manifest.json`, +2. **Packaged output**. This is a folder that contains a `companion/manifest.json`, `companion/HELP.md`, `package.json`, `main.js` (or another name), and possibly a few other files. No extra work is needed for this to be loaded diff --git a/for-developers/module-development/module-lifecycle/renaming-your-module.md b/for-developers/module-development/module-lifecycle/renaming-your-module.md index ac1d16c..3aa711e 100644 --- a/for-developers/module-development/module-lifecycle/renaming-your-module.md +++ b/for-developers/module-development/module-lifecycle/renaming-your-module.md @@ -9,7 +9,7 @@ Occasionally you will need to rename a module, perhaps for example, to make the name more inclusive as you add more devices, or the manufacturer releases a new device. -1. Ask in the module-development slack for approval on the new name This is so +1. Ask in the module-development slack for approval on the new name. This is so that we can be sure the new name conforms to our standard structure of `companion-module-manufacturer-product` (or `companion-module-manufacturer-protocol`). diff --git a/for-developers/module-development/module-setup/typescript-config.md b/for-developers/module-development/module-setup/typescript-config.md index 3683ad8..2b0f5fb 100644 --- a/for-developers/module-development/module-setup/typescript-config.md +++ b/for-developers/module-development/module-setup/typescript-config.md @@ -28,7 +28,7 @@ A typical _tsconfig.json_ file looks like: "node_modules/**", "src/**/*spec.ts", "src/**/__tests__/*", - "src/**/__mocks__/*", + "src/**/__mocks__/*" ], "compilerOptions": { "outDir": "./dist", @@ -63,7 +63,7 @@ Our TypeScript template splits it into two files: "node_modules/**", "src/**/*spec.ts", "src/**/__tests__/*", - "src/**/__mocks__/*", + "src/**/__mocks__/*" ], "compilerOptions": { "outDir": "./dist", From 88fb9520f436d1f60dc13c23199c236d911ff14f Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Mon, 2 Mar 2026 17:07:20 -0800 Subject: [PATCH 11/12] prettier also fix code blocks marked as "jsonc" to just "json" so they format correctly --- .../module-development/api-changes/v2.0.md | 13 +++++++---- .../module-development/local-modules.md | 11 +++++----- .../module-setup/typescript-config.md | 22 +++++++++---------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/for-developers/module-development/api-changes/v2.0.md b/for-developers/module-development/api-changes/v2.0.md index e2d54e6..3f3bbe8 100644 --- a/for-developers/module-development/api-changes/v2.0.md +++ b/for-developers/module-development/api-changes/v2.0.md @@ -6,9 +6,12 @@ description: TypeScript improvements).' --- -This is a major series of changes — the first breaking changes since Companion 3.0, over three years in the making. +This is a major series of changes — the first breaking changes since Companion +3.0, over three years in the making. -If you are not ready to tackle these changes, there is no rush. Many of the changes improve module functionality, but API 1.x remains fully supported and there are no plans to remove that support. +If you are not ready to tackle these changes, there is no rush. Many of the +changes improve module functionality, but API 1.x remains fully supported and +there are no plans to remove that support. ## Required changes @@ -39,9 +42,11 @@ JavaScript module. ### Minimum @companion-module/tools version -In order to build your module correctly, you need to be using `@companion-module/tools` v2.7.1 or later +In order to build your module correctly, you need to be using +`@companion-module/tools` v2.7.1 or later -We will soon be releasing a v3.0.0 which will optimise the build process further and should be a drop in replacement. +We will soon be releasing a v3.0.0 which will optimise the build process further +and should be a drop in replacement. ### Remove `runEntrypoint` method diff --git a/for-developers/module-development/local-modules.md b/for-developers/module-development/local-modules.md index 54534f2..ab4fbb3 100644 --- a/for-developers/module-development/local-modules.md +++ b/for-developers/module-development/local-modules.md @@ -16,12 +16,13 @@ module folder is specified as described below. Inside of this folder should be one or more folders that use the following layouts, with each folder corresponding to a different module. -1. **A git clone of a module from github**. This requires some additional setup, as - the module will need to be prepared with a `yarn install`, and for some, a +1. **A git clone of a module from github**. This requires some additional setup, + as the module will need to be prepared with a `yarn install`, and for some, a `yarn build`. -2. **Packaged output**. This is a folder that contains a `companion/manifest.json`, - `companion/HELP.md`, `package.json`, `main.js` (or another name), and - possibly a few other files. No extra work is needed for this to be loaded +2. **Packaged output**. This is a folder that contains a + `companion/manifest.json`, `companion/HELP.md`, `package.json`, `main.js` (or + another name), and possibly a few other files. No extra work is needed for + this to be loaded ## Set up a developer folder diff --git a/for-developers/module-development/module-setup/typescript-config.md b/for-developers/module-development/module-setup/typescript-config.md index 2b0f5fb..5d33423 100644 --- a/for-developers/module-development/module-setup/typescript-config.md +++ b/for-developers/module-development/module-setup/typescript-config.md @@ -20,7 +20,7 @@ the name of the source or destination directories. A typical _tsconfig.json_ file looks like: -```jsonc +```json { "extends": "@companion-module/tools/tsconfig/node22/recommended", "include": ["src/**/*.ts"], @@ -34,27 +34,27 @@ A typical _tsconfig.json_ file looks like: "outDir": "./dist", "baseUrl": "./", "paths": { - "*": ["./node_modules/*"], - }, - }, + "*": ["./node_modules/*"] + } + } } ``` Our TypeScript template splits it into two files: -```jsonc +```json //tsconfig.json { "extends": "./tsconfig.build.json", "include": ["src/**/*.ts"], "exclude": ["node_modules/**"], "compilerOptions": { - "types": ["node"], - }, + "types": ["node"] + } } ``` -```jsonc +```json // tsconfig.build.json { "extends": "@companion-module/tools/tsconfig/node22/recommended", @@ -69,11 +69,11 @@ Our TypeScript template splits it into two files: "outDir": "./dist", "baseUrl": "./", "paths": { - "*": ["./node_modules/*"], + "*": ["./node_modules/*"] }, "module": "Node16", - "moduleResolution": "Node16", - }, + "moduleResolution": "Node16" + } } ``` From c55835c37abcb6c5b8133772c70df7d3832759f8 Mon Sep 17 00:00:00 2001 From: Ari Kornfeld Date: Mon, 2 Mar 2026 18:41:42 -0800 Subject: [PATCH 12/12] fix: clean up variables syntax, hopefully --- .../connection-basics/variables.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/for-developers/module-development/connection-basics/variables.md b/for-developers/module-development/connection-basics/variables.md index 34b63cd..ad652bd 100644 --- a/for-developers/module-development/connection-basics/variables.md +++ b/for-developers/module-development/connection-basics/variables.md @@ -16,9 +16,10 @@ are defined by the module InstanceBase class. ## API call: `setVariableDefinitions()` Your module should define the list of variables it exposes by making a call to -`this.setVariableDefinitions([ ...some variables here... ])`. You will need to -do this as part of your `init()` method, but can also call it at any other time -if you wish to change the list of variables exposed. +`this.setVariableDefinitions(...some variables here...)` -- the exact format +depends on the module API you are using; see below. You will need to do this as +part of your `init()` method, but can also call it at any other time if you wish +to change the list of variables exposed. :::warning @@ -39,8 +40,8 @@ split the variable definitions into even more files/folders. ### API 2.x -All the variable definitions are passed in as a single JavaScript object, in the -form of: +All the variable definitions are passed in as a single JavaScript _object_, in +the form of: ```js const definitions = { @@ -58,8 +59,8 @@ VariableId must only use letters [a-zA-Z], numbers, underscore, hyphen. ### API 1.x -All the variable definitions are passed in as a single JavaScript array, in the -form of: +All the variable definitions are passed in as a single JavaScript _array_, in +the form of: ```js const definitions = [