Skip to content

Commit

Permalink
feat: add support for Stream Deck 6.8 (#12)
Browse files Browse the repository at this point in the history
* feat: add 6.8, and migration documentation

* docs: update summary of font.size to indicate measurement type

* chore: fix linting

* refactor: move 6.7 and 6.8 into 6.6, and improve migration documentation

---------

Co-authored-by: Richard Herman <[email protected]>
  • Loading branch information
GeekyEggo and GeekyEggo authored Oct 14, 2024
1 parent 7858ffb commit b3e9ffa
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 81 deletions.
62 changes: 62 additions & 0 deletions src/streamdeck/plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Stream Deck Plugin Schemas

## Manifest

Manifest versioning is achieved using reverse-migrations, by extending the versions successor and utilizing the `Omit` utility type to _remove_ new features, for example:

```mermaid
classDiagram
Manifest <|-- Manifest_6_6
Manifest_6_6 <|-- Manifest_6_5
class Manifest {
+ string: Software.MinimumVersion
...
}
class Manifest_6_6 {
+ "6.6" | "6.7": Software.MinimumVersion
// No changes introduced from 6.6 to 6.7.
}
class Manifest_6_5 {
+ "6.5": Software.MinimumVersion
// Changes introduced from 6.5 to 6.6, omit new properties.
}
```

### Glossary

- vLatest — The current version, with a flat `Software.MinimumVersion`.
- vCurrent — The current version, for example `v6.7.ts`.
- vNext — The new version being introduced, for example `v6.8.ts`.

### File Structure Example

Manifest versions, and the type responsible for generating the JSON schema, are located in the following file structure:

```
./src/streamdeck/plugins/
├── manifest/
│ ├── latest.ts # vLatest — vCurrent, with flat Software.MinimumVersion, e.g. "6.5" | "6.6" | "6.7"
| ├── v6.5.ts
| ├── v6.6.ts
| └── v6.7.ts # vCurrent, with specific Software.MinimumVersion, e.g. "6.7"
└── schemas.ts
```

### Adding Versions of Stream Deck

When adding a new version of Stream Deck, its important to consider if there are manifest changes. If simply adding a new version of `Software.MinimumVersion`, vCurrent can be updated to include the new version. If there are new properties introduced, a reverse-migration is needed.

The following flowchart depicts how to introduce a new version of Stream Deck to the manifest type and JSON schema.

```mermaid
graph TD;
a("New version of<br />Stream Deck app")-->b
b{"Manifest<br />changes"}
b-->|Yes|y0("Add changes to ./manifest/latest.ts")
y0-->y1("Create vNext (e.g. v6.8.ts) in ./manifest/ — extend latest, and re-set Software.MinimumVersion")
y1-->y2("Update vCurrent in ./manifest/ — extend vNext, and omit changes")
y2-->y3("Update Manifest type within ./schemas/ to include vNext")-->z0
b-->|No|n("Update vCurrent Software.MinimumVersion to include new version")-->z0
z0("Add unit tests for new version")
z0-->z1("Fin")
```
5 changes: 3 additions & 2 deletions src/streamdeck/plugins/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,9 @@ export type Text = LayoutItemBase<"text"> & {
*/
font?: {
/**
* Size of the font. **Note**, when the `key` of this layout item is set to `"title"` within the layout's JSON definition, this value will be ignored in favour of the user's
* preferred title settings, as set in property inspector.
* Size of the font, in pixels, represented as a whole number.
*
* **Note**, when the `key` of this layout item is set to `"title"` within the layout's JSON definition, this value will be ignored in favour of the user's preferred title settings, as set in property inspector.
*/
size?: number;

Expand Down
2 changes: 1 addition & 1 deletion src/streamdeck/plugins/manifest/__tests__/all.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { validateStreamDeckPluginManifest } from "@tests";

describe.each(["v6.4", "v6.5", "v6.6", "v6.7"])("%s", (version) => {
describe.each(["v6.4", "v6.5", "v6.6", "v6.7", "v6.8"])("%s", (version) => {
const filePath = `${version}.json`;

/**
Expand Down
91 changes: 91 additions & 0 deletions src/streamdeck/plugins/manifest/__tests__/files/v6.8.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"$schema": "../../../../../../streamdeck/plugins/manifest.json",
"Actions": [
{
"Controllers": ["Encoder", "Keypad"],
"DisableAutomaticStates": true,
"DisableCaching": false,
"Encoder": {
"background": "background",
"Icon": "icon",
"layout": "$A0",
"StackColor": "#000000",
"TriggerDescription": {
"LongTouch": "Long touch",
"Push": "Push",
"Rotate": "Rotate",
"Touch": "Touch"
}
},
"Icon": "action-icon",
"Name": "Action One",
"OS": ["mac", "windows"],
"PropertyInspectorPath": "action.html",
"States": [
{
"FontFamily": "Arial",
"FontSize": 12,
"FontStyle": "Bold",
"FontUnderline": true,
"Image": "action-state-image",
"MultiActionImage": "action-state-multi-action-image",
"Name": "Action State One",
"ShowTitle": true,
"Title": "State One",
"TitleAlignment": "bottom",
"TitleColor": "#000000"
}
],
"SupportedInMultiActions": true,
"Tooltip": "This is the tooltip",
"UserTitleEnabled": true,
"UUID": "com.elgato.test.one",
"VisibleInActionsList": true
}
],
"ApplicationsToMonitor": {
"mac": ["finder"],
"windows": ["explorer.exe"]
},
"Author": "Elgato",
"Category": "Testing",
"CategoryIcon": "category-icon",
"CodePath": "main.js",
"CodePathMac": "main-darwin.js",
"CodePathWin": "main-windows.js",
"DefaultWindowSize": [500, 650],
"Description": "Manifest version 6.4",
"Icon": "icon",
"Name": "Test Manifest",
"Nodejs": {
"Debug": "break",
"GenerateProfilerOutput": false,
"Version": "20"
},
"OS": [
{
"MinimumVersion": "13",
"Platform": "mac"
},
{
"MinimumVersion": "10",
"Platform": "windows"
}
],
"Profiles": [
{
"DeviceType": 7,
"DontAutoSwitchWhenInstalled": true,
"Name": "Test Profile",
"Readonly": true
}
],
"PropertyInspectorPath": "pi.html",
"SDKVersion": 2,
"Software": {
"MinimumVersion": "6.8"
},
"URL": "https://www.elgato.com",
"UUID": "com.elgato.test",
"Version": "1.0.0.0"
}
16 changes: 7 additions & 9 deletions src/streamdeck/plugins/manifest/__tests__/v6.6.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { validateStreamDeckPluginManifest } from "@tests";

const VERSION = "6.6";

describe("v6.6", () => {
describe.each(["6.6" as const, "6.7" as const, "6.8" as const])("v%s", (version) => {
/**
* Asserts a valid v6.6 manifest.
* Asserts the full manifest.
*/
test("full manifest", () => {
// Arrange, act, assert.
const errors = validateStreamDeckPluginManifest("v6.6.json");
const errors = validateStreamDeckPluginManifest(`v${version}.json`);
expect(errors).toHaveLength(0);
});

Expand All @@ -17,21 +15,21 @@ describe("v6.6", () => {
*/
test("Actions[].States[] allow more than 2 items", () => {
// Arrange, act, assert.
const errors = validateStreamDeckPluginManifest("v6.6.json", (m) => {
const errors = validateStreamDeckPluginManifest(`v${version}.json`, (m) => {
m.Actions[0].States.push({ Image: "imgs/two" });
m.Actions[0].States.push({ Image: "imgs/three" });
m.Actions[0].States.push({ Image: "imgs/four" });
});
expect(errors).toHaveLength(0);
});

describe("v6.6 features", () => {
describe(`v${version} feature compatibility`, () => {
/**
* Asserts `Actions[].OS` is not valid for a v6.5 manifest.
*/
test("Actions[].OS is valid", () => {
// Arrange, act, assert.
const errors = validateStreamDeckPluginManifest("Actions[].OS.json", (m) => (m.Software.MinimumVersion = VERSION));
const errors = validateStreamDeckPluginManifest("Actions[].OS.json", (m) => (m.Software.MinimumVersion = version));
expect(errors).toHaveLength(0);
});

Expand All @@ -40,7 +38,7 @@ describe("v6.6", () => {
*/
test("Profiles[].AutoInstall is valid", () => {
// Arrange, act, assert.
const errors = validateStreamDeckPluginManifest("Profiles[].AutoInstall.json", (m) => (m.Software.MinimumVersion = VERSION));
const errors = validateStreamDeckPluginManifest("Profiles[].AutoInstall.json", (m) => (m.Software.MinimumVersion = version));
expect(errors).toHaveLength(0);
});
});
Expand Down
47 changes: 0 additions & 47 deletions src/streamdeck/plugins/manifest/__tests__/v6.7.test.ts

This file was deleted.

3 changes: 2 additions & 1 deletion src/streamdeck/plugins/manifest/latest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DeviceType } from "../device-type";
import type { Manifest as ManifestSchema } from "../schemas";

/**
* Determines the Stream Deck software requirements for this plugin.
Expand All @@ -7,7 +8,7 @@ export type Software = {
/**
* Minimum version of the Stream Deck application required for this plugin to run.
*/
MinimumVersion: "6.4" | "6.5" | "6.6" | "6.7";
MinimumVersion: ManifestSchema["Software"]["MinimumVersion"];
};

/**
Expand Down
6 changes: 3 additions & 3 deletions src/streamdeck/plugins/manifest/v6.6.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import type { Manifest_6_7 } from "./v6.7";
import type { Manifest } from "./latest";

/**
* Defines the plugin and available actions, and all information associated with them, including the plugin's entry point, all iconography, action default behavior, etc.
*/
export type Manifest_6_6 = Omit<Manifest_6_7, "Software"> & {
export type Manifest_6_6 = Omit<Manifest, "Software"> & {
/**
* Determines the Stream Deck software requirements for this plugin.
*/
Software: {
/**
* Minimum version of the Stream Deck application required for this plugin to run.
*/
MinimumVersion: "6.6";
MinimumVersion: "6.6" | "6.7" | "6.8";
};
};
16 changes: 0 additions & 16 deletions src/streamdeck/plugins/manifest/v6.7.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/streamdeck/plugins/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { type Manifest_6_4 } from "./manifest/v6.4";
import { type Manifest_6_5 } from "./manifest/v6.5";
import { type Manifest_6_6 } from "./manifest/v6.6";
import { type Manifest_6_7 } from "./manifest/v6.7";

/**
* Defines the plugin and available actions, and all information associated with them, including the plugin's entry point, all iconography, action default behavior, etc.
*/
export type Manifest = JsonSchema<Manifest_6_4> | JsonSchema<Manifest_6_5> | JsonSchema<Manifest_6_6> | JsonSchema<Manifest_6_7>;
export type Manifest = JsonSchema<Manifest_6_4> | JsonSchema<Manifest_6_5> | JsonSchema<Manifest_6_6>;

export type { Layout } from "./layout";

Expand Down

0 comments on commit b3e9ffa

Please sign in to comment.