Skip to content

Commit

Permalink
feat: add routing of messages between the property inspector and the …
Browse files Browse the repository at this point in the history
…plugin (#33)

* feat: add infrastructure for routing messages between plugin and ui

* fix: allow event emitter to be untyped

* refactor: rename host to gateway

* fix: payload types and constraints

* fix: provide default type

* feat: emit unknownMessage and unknownRequest from gateway

* build: remove rollup bundling of declarations to prevent loss of summaries

Sadly, when utilizing rollup-plugin-dts to bundle declarations into a single file, summaries for "export import *" were being lost. This result in quiet issues when creating the .d.ts file, so has [temporarily] been removed.

* build: tidy-up rollup

* feat: add default generics to support SingletonAction

* feat: return 406 when the proxy could not accept the request

* fix: re-introduce logging to the connection

* feat: add routing and fetch to ui and plugin namespaces

* test: improve testing compatibility

* Revert "build: remove rollup bundling of declarations to prevent loss of summaries"

This partially reverts commit b91556f.

* feat: introduce UIController, and property inspector tracking

* refactor: replace UI namespace with UIController

* feat: add PluginController to property  inspector

* feat: add initial @route decorator

* refactor: abstract PropertyInspector class to separate file

* fix: export PI type

* docs: standardize summaries

* test: route decorator

* test: fix types

* refactor: rename internal message request to prevent declaration rename

* test: fix UI controller tests

* fix: exported types

* refactor: undo renaming of sendToPlugin and sendToPropertyInspector events

* refactor: mark sendToPropertyInspector as deprecated

* refactor: mark sendToPlugin as deprecated

* docs: add examples to fetch

* docs: add year to license

* feat: update registerRoute to return a disposable

* test: remove debugging

---------

Co-authored-by: Richard Herman <[email protected]>
  • Loading branch information
GeekyEggo and GeekyEggo authored Apr 10, 2024
1 parent e4567ec commit 08f1d7b
Show file tree
Hide file tree
Showing 57 changed files with 3,144 additions and 483 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
### 🐞 Fix

- `Coordinates` type could erroneously have a non-number type for `row`.
- Fix support for allowed types within payloads.

### ♻️ Update

- Update layout and manifest references to propagate from [`@elgato/schemas`](https://github.com/elgatosf/schemas).

### ➡️ Migration

- `streamDeck.ui.onSendToPlugin` renamed to `streamDeck.ui.onDidReceivePropertyInspectorMessage`.
- `SendToPluginEvent<T>` renamed to `DidReceivePropertyInspectorPayloadEvent<T>`.
- `PayloadObject<T>` replaced with `JsonObject`.
- JSON schemas have been relocated to a dedicated schemas package, [`@elgato/schemas`](https://github.com/elgatosf/schemas).

## 0.3.0
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Corsair Memory Inc.
Copyright (c) 2024 Corsair Memory Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 4 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const config = {
parser: {
syntax: "typescript",
decorators: true
},
transform: {
// Stage 3 decorators (https://swc.rs/docs/configuration/compilation#jsctransformdecoratorversion)
decoratorVersion: "2022-03"
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/api/command.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { JsonValue } from "../plugin";
import type { ActionIdentifier, DidReceiveGlobalSettings, DidReceiveSettings, State } from "./events";
import type { FeedbackPayload } from "./layout";
import type { Target } from "./target";
Expand Down Expand Up @@ -233,12 +234,12 @@ export type SwitchToProfile = ContextualizedCommand<
/**
* Sends a message to the property inspector.
*/
export type SendToPropertyInspector = ContextualizedCommand<"sendToPropertyInspector", unknown>;
export type SendToPropertyInspector<TPayload extends JsonValue = JsonValue> = ContextualizedCommand<"sendToPropertyInspector", TPayload>;

/**
* Sends a message to the plugin.
*/
export type SendToPlugin = ActionIdentifier & CommandBase<"sendToPlugin", unknown>;
export type SendToPlugin<TPayload extends JsonValue = JsonValue> = ActionIdentifier & CommandBase<"sendToPlugin", TPayload>;

/**
* Command sent to Stream Deck, from the plugin.
Expand Down
22 changes: 10 additions & 12 deletions src/api/events/action.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import type { Controller, DeviceType } from "@elgato/schemas/streamdeck/plugins";
import type { JsonObject } from "../../common/json";
import type { DeviceIdentifier } from "./device";
import type { EventIdentifier, PayloadObject } from "./index";
import type { EventIdentifier } from "./index";

/**
* Occurs when the settings associated with an action instance are requested, or when the the settings were updated by the property inspector.
*/
export type DidReceiveSettings<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<
"didReceiveSettings",
MultiActionPayload<TSettings> | SingleActionPayload<TSettings>
>;
export type DidReceiveSettings<TSettings extends JsonObject> = ActionEventMessage<"didReceiveSettings", MultiActionPayload<TSettings> | SingleActionPayload<TSettings>>;

/**
* Occurs when the user updates an action's title settings in the Stream Deck application.
*/
export type TitleParametersDidChange<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<
export type TitleParametersDidChange<TSettings extends JsonObject> = ActionEventMessage<
"titleParametersDidChange",
Omit<SingleActionPayload<TSettings>, "isInMultiAction"> & {
/**
Expand Down Expand Up @@ -68,13 +66,13 @@ export type TitleParametersDidChange<TSettings extends PayloadObject<TSettings>>
* page". An action refers to _all_ types of actions, e.g. keys, dials,
* touchscreens, pedals, etc.
*/
export type WillAppear<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"willAppear", MultiActionPayload<TSettings> | SingleActionPayload<TSettings>>;
export type WillAppear<TSettings extends JsonObject> = ActionEventMessage<"willAppear", MultiActionPayload<TSettings> | SingleActionPayload<TSettings>>;

/**
* Occurs when an action disappears from the Stream Deck due to the user navigating to another page, profile, folder, etc. An action refers to _all_ types of actions, e.g. keys, dials,
* touchscreens, pedals, etc.
*/
export type WillDisappear<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"willDisappear", MultiActionPayload<TSettings> | SingleActionPayload<TSettings>>;
export type WillDisappear<TSettings extends JsonObject> = ActionEventMessage<"willDisappear", MultiActionPayload<TSettings> | SingleActionPayload<TSettings>>;

/**
* Provide information that identifies an action associated with an event.
Expand Down Expand Up @@ -109,7 +107,7 @@ export type ActionEventMessage<TEvent extends string, TPayload = void> = DeviceI
/**
* Additional information about the action and event that occurred as part of a single-action event.
*/
export type SingleActionPayload<TSettings extends PayloadObject<TSettings>, TController extends Controller = Controller> = ActionPayload<TSettings> & {
export type SingleActionPayload<TSettings extends JsonObject, TController extends Controller = Controller> = ActionPayload<TSettings> & {
/**
* Coordinates that identify the location of an action.
*/
Expand All @@ -130,7 +128,7 @@ export type SingleActionPayload<TSettings extends PayloadObject<TSettings>, TCon
/**
* Additional information about the action and event that occurred as part of a multi-action event.
*/
export type MultiActionPayload<TSettings extends PayloadObject<TSettings>> = ActionPayload<TSettings> & {
export type MultiActionPayload<TSettings extends JsonObject> = ActionPayload<TSettings> & {
/**
* Defines the controller type the action is applicable to. **Keypad** refers to a standard action on a Stream Deck device, e.g. 1 of the 15 buttons on the Stream Deck MK.2,
* or a pedal on the Stream Deck Pedal, etc., whereas an **Encoder** refers to a dial / touchscreen on the Stream Deck+.
Expand All @@ -148,11 +146,11 @@ export type MultiActionPayload<TSettings extends PayloadObject<TSettings>> = Act
/**
* Base payload provided as part of events received, relating to an action.
*/
type ActionPayload<TSettings extends PayloadObject<TSettings>> = {
type ActionPayload<TSettings extends JsonObject> = {
/**
* Settings associated with the action instance.
*/
settings: PayloadObject<TSettings>;
settings: TSettings;

/**
* Current state of the action; only applicable to actions that have multiple states defined within the `manifest.json` file.
Expand Down
12 changes: 6 additions & 6 deletions src/api/events/encoder.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import type { JsonObject } from "../../common/json";
import type { ActionEventMessage, Coordinates, SingleActionPayload } from "./action";
import type { PayloadObject } from "./index";
import type { KeyDown, KeyUp } from "./keypad";

/**
* Occurs when the user presses a dial (Stream Deck+).Also see {@link DialUp}.
*
* NB: For other action types see {@link KeyDown}.
*/
export type DialDown<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"dialDown", EncoderPayload<TSettings>>;
export type DialDown<TSettings extends JsonObject> = ActionEventMessage<"dialDown", EncoderPayload<TSettings>>;

/**
* Occurs when the user releases a pressed dial (Stream Deck+).Also see {@link DialDown}.
*
* NB: For other action types see {@link KeyUp}.
*/
export type DialUp<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"dialUp", EncoderPayload<TSettings>>;
export type DialUp<TSettings extends JsonObject> = ActionEventMessage<"dialUp", EncoderPayload<TSettings>>;

/**
* Occurs when the user rotates a dial (Stream Deck+).
*/
export type DialRotate<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<
export type DialRotate<TSettings extends JsonObject> = ActionEventMessage<
"dialRotate",
EncoderPayload<TSettings> & {
/**
Expand All @@ -37,7 +37,7 @@ export type DialRotate<TSettings extends PayloadObject<TSettings>> = ActionEvent
/**
* Occurs when the user taps the touchscreen (Stream Deck+).
*/
export type TouchTap<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<
export type TouchTap<TSettings extends JsonObject> = ActionEventMessage<
"touchTap",
EncoderPayload<TSettings> & {
/**
Expand All @@ -55,7 +55,7 @@ export type TouchTap<TSettings extends PayloadObject<TSettings>> = ActionEventMe
/**
* Additional information about the action and event that occurred.
*/
type EncoderPayload<TSettings extends PayloadObject<TSettings>> = Pick<SingleActionPayload<TSettings, "Encoder">, "controller" | "settings"> & {
type EncoderPayload<TSettings extends JsonObject> = Pick<SingleActionPayload<TSettings, "Encoder">, "controller" | "settings"> & {
/**
* Coordinates that identify the location of the action.
*/
Expand Down
34 changes: 15 additions & 19 deletions src/api/events/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { JsonObject, JsonValue } from "../../common/json";
import type { DidReceiveSettings, TitleParametersDidChange, WillAppear, WillDisappear } from "./action";
import type { DeviceDidConnect, DeviceDidDisconnect } from "./device";
import type { DialDown, DialRotate, DialUp, TouchTap } from "./encoder";
Expand Down Expand Up @@ -26,35 +27,30 @@ export type EventIdentifier<TEvent> = {
readonly event: TEvent;
};

/**
* Represents an object sent as part of Stream Deck's API.
*/
export type PayloadObject<T extends object> = { [K in keyof T]: T[K] } extends RelativeIndexable<unknown> ? never : { [K in keyof T]: T[K] };

/**
* Events received by the plugin, from Stream Deck.
*/
export type PluginEvent<T extends PayloadObject<T> = object> =
export type PluginEvent =
| ApplicationDidLaunch
| ApplicationDidTerminate
| DeviceDidConnect
| DeviceDidDisconnect
| DialDown<T>
| DialRotate<T>
| DialUp<T>
| DialDown<JsonObject>
| DialRotate<JsonObject>
| DialUp<JsonObject>
| DidReceiveDeepLink
| DidReceiveGlobalSettings<T>
| DidReceivePropertyInspectorMessage<T>
| DidReceiveSettings<T>
| KeyDown<T>
| KeyUp<T>
| DidReceiveGlobalSettings<JsonObject>
| DidReceivePropertyInspectorMessage<JsonValue>
| DidReceiveSettings<JsonObject>
| KeyDown<JsonObject>
| KeyUp<JsonObject>
| PropertyInspectorDidAppear
| PropertyInspectorDidDisappear
| SystemDidWakeUp
| TitleParametersDidChange<T>
| TouchTap<T>
| WillAppear<T>
| WillDisappear<T>;
| TitleParametersDidChange<JsonObject>
| TouchTap<JsonObject>
| WillAppear<JsonObject>
| WillDisappear<JsonObject>;

/**
* Map of events received by the plugin, from Stream Deck.
Expand All @@ -66,7 +62,7 @@ export type PluginEventMap = {
/**
* Events received by the UI, from Stream Deck.
*/
export type UIEvent<T extends PayloadObject<T> = object> = DidReceiveGlobalSettings<T> | DidReceivePluginMessage<T> | DidReceiveSettings<T>;
export type UIEvent = DidReceiveGlobalSettings<JsonObject> | DidReceivePluginMessage<JsonValue> | DidReceiveSettings<JsonObject>;

/**
* Map of events received by the UI, from Stream Deck.
Expand Down
8 changes: 4 additions & 4 deletions src/api/events/keypad.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import type { JsonObject } from "../../common/json";
import type { ActionEventMessage, MultiActionPayload, SingleActionPayload, State } from "./action";
import type { DialDown, DialUp } from "./encoder";
import type { PayloadObject } from "./index";

/**
* Occurs when the user presses a action down. Also see {@link KeyUp}.
*
* NB: For dials / touchscreens see {@link DialDown}.
*/
export type KeyDown<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"keyDown", KeypadPayload<TSettings>>;
export type KeyDown<TSettings extends JsonObject> = ActionEventMessage<"keyDown", KeypadPayload<TSettings>>;

/**
* Occurs when the user releases a pressed action. Also see {@link KeyDown}.
*
* NB: For dials / touchscreens see {@link DialUp}.
*/
export type KeyUp<TSettings extends PayloadObject<TSettings>> = ActionEventMessage<"keyUp", KeypadPayload<TSettings>>;
export type KeyUp<TSettings extends JsonObject> = ActionEventMessage<"keyUp", KeypadPayload<TSettings>>;

/**
* Additional information about a keypad event that occurred.
*/
type KeypadPayload<TSettings extends PayloadObject<TSettings>> =
type KeypadPayload<TSettings extends JsonObject> =
| SingleActionPayload<TSettings, "Keypad">
| (MultiActionPayload<TSettings> & {
/**
Expand Down
7 changes: 4 additions & 3 deletions src/api/events/system.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Manifest } from "../";
import type { EventIdentifier, PayloadObject } from "./index";
import type { JsonObject } from "../../common/json";
import type { EventIdentifier } from "./index";

/**
* Occurs when a monitored application is launched. Monitored applications can be defined in the `manifest.json` file via the {@link Manifest.ApplicationsToMonitor} property. Also see
Expand All @@ -16,15 +17,15 @@ export type ApplicationDidTerminate = ApplicationEventIdentifier<"applicationDid
/**
* Occurs when the plugin receives the global settings from the Stream Deck.
*/
export type DidReceiveGlobalSettings<TSettings extends PayloadObject<TSettings>> = EventIdentifier<"didReceiveGlobalSettings"> & {
export type DidReceiveGlobalSettings<TSettings extends JsonObject> = EventIdentifier<"didReceiveGlobalSettings"> & {
/**
* Additional information about the event that occurred.
*/
readonly payload: {
/**
* Global settings associated with this plugin.
*/
settings: PayloadObject<TSettings>;
settings: TSettings;
};
};

Expand Down
8 changes: 4 additions & 4 deletions src/api/events/ui.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { JsonValue } from "../../common/json";
import type { ActionEventMessage } from "./action";
import type { DeviceIdentifier } from "./device";
import type { PayloadObject } from "./index";

/**
* Occurs when the property inspector associated with the action becomes visible, i.e. the user selected an action in the Stream Deck application. Also see {@link PropertyInspectorDidDisappear}.
Expand All @@ -15,7 +15,7 @@ export type PropertyInspectorDidDisappear = ActionEventMessage<"propertyInspecto
/**
* Message sent between the plugin and it's respective UI.
*/
type PluginMessage<TEvent extends string, TPayload extends PayloadObject<TPayload>> = Omit<ActionEventMessage<TEvent>, keyof DeviceIdentifier> & {
type PluginMessage<TEvent extends string, TPayload extends JsonValue> = Omit<ActionEventMessage<TEvent>, keyof DeviceIdentifier> & {
/**
* Payload sent between the plugin and it's UI.
*/
Expand All @@ -25,9 +25,9 @@ type PluginMessage<TEvent extends string, TPayload extends PayloadObject<TPayloa
/**
* Occurs when a payload was received from the UI.
*/
export type DidReceivePropertyInspectorMessage<TPayload extends PayloadObject<TPayload>> = PluginMessage<"sendToPlugin", TPayload>;
export type DidReceivePropertyInspectorMessage<TPayload extends JsonValue> = PluginMessage<"sendToPlugin", TPayload>;

/**
* Occurs when a message was received from the plugin.
*/
export type DidReceivePluginMessage<TPayload extends PayloadObject<TPayload>> = PluginMessage<"sendToPropertyInspector", TPayload>;
export type DidReceivePluginMessage<TPayload extends JsonValue> = PluginMessage<"sendToPropertyInspector", TPayload>;
Loading

0 comments on commit 08f1d7b

Please sign in to comment.