@crowbartools/firebot-types 5.67.0-alpha20 → 5.67.0-alpha21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/backend/common/settings-manager.d.ts +0 -4
  2. package/backend/control-deck/builtin-control-types/button.d.ts +6 -0
  3. package/backend/control-deck/builtin-control-types/folder.d.ts +6 -0
  4. package/backend/control-deck/builtin-control-types/switch.d.ts +11 -0
  5. package/backend/control-deck/control-deck-manager.d.ts +7 -1
  6. package/backend/control-deck/control-deck-state-manager.d.ts +18 -0
  7. package/backend/control-deck/control-type-manager.d.ts +13 -0
  8. package/backend/effects/builtin/chat.d.ts +3 -0
  9. package/backend/notifications/notification-manager.d.ts +2 -1
  10. package/backend/plugins/executors/plugin-executor.interface.d.ts +4 -0
  11. package/backend/plugins/plugin-config-manager.d.ts +0 -2
  12. package/backend/plugins/plugin-manager.d.ts +1 -0
  13. package/backend/restrictions/builtin/active-chat-users.d.ts +1 -1
  14. package/backend/restrictions/builtin/channel-currency.d.ts +1 -1
  15. package/backend/restrictions/builtin/channel-game.d.ts +1 -1
  16. package/backend/restrictions/builtin/chat-messages.d.ts +1 -1
  17. package/backend/restrictions/builtin/custom-variable.d.ts +1 -1
  18. package/backend/restrictions/builtin/follow-check.d.ts +1 -1
  19. package/backend/restrictions/builtin/limit-per-stream.d.ts +1 -1
  20. package/backend/restrictions/builtin/only-when-live.d.ts +1 -1
  21. package/backend/restrictions/builtin/permissions.d.ts +1 -1
  22. package/backend/restrictions/builtin/time-range.d.ts +1 -1
  23. package/backend/restrictions/builtin/view-time.d.ts +1 -1
  24. package/backend/restrictions/builtin/viewer-count.d.ts +1 -1
  25. package/backend/restrictions/restriction-manager.d.ts +2 -3
  26. package/backend/streaming-platforms/twitch/api/index.d.ts +1 -0
  27. package/backend/streaming-platforms/twitch/api/resource/api-resource-base.d.ts +1 -0
  28. package/backend/streaming-platforms/twitch/api/resource/chat.d.ts +50 -5
  29. package/backend/streaming-platforms/twitch/effects/pin-chat-message.d.ts +6 -0
  30. package/backend/streaming-platforms/twitch/effects/unpin-chat-message.d.ts +3 -0
  31. package/backend/streaming-platforms/twitch/effects/update-pinned-chat-message.d.ts +6 -0
  32. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/index.d.ts +2 -0
  33. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-by-user-display-name.d.ts +3 -0
  34. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-by-user-id.d.ts +3 -0
  35. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-by-username.d.ts +3 -0
  36. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message-id.d.ts +3 -0
  37. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message-text-only.d.ts +3 -0
  38. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message-user-display-name.d.ts +3 -0
  39. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message-user-id.d.ts +3 -0
  40. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message-username.d.ts +3 -0
  41. package/backend/streaming-platforms/twitch/variables/chat/pinned-message/pinned-chat-message.d.ts +3 -0
  42. package/package.json +1 -1
  43. package/types/control-deck.d.ts +120 -30
  44. package/types/parameters.d.ts +3 -0
  45. package/types/plugin-api.d.ts +0 -10
  46. package/types/plugins.d.ts +2 -1
  47. package/types/restrictions.d.ts +5 -1
  48. package/types/settings.d.ts +0 -1
  49. package/types/ui/control-deck-service.d.ts +8 -0
  50. package/types/ui/index.d.ts +1 -0
  51. package/types/ui-extensions.d.ts +5 -0
  52. package/types/util-types.d.ts +4 -0
  53. /package/{backend → server}/bonjour-manager.d.ts +0 -0
@@ -77,10 +77,6 @@ declare class SettingsManager extends TypedEmitter<Events> {
77
77
  getOverlayVersion: () => string;
78
78
  /** @deprecated Use `saveSetting("CopiedOverlayVersion", value)` instead */
79
79
  setOverlayVersion: (value: string) => void;
80
- /** @deprecated Use `getSetting("ClearCustomScriptCache")` instead */
81
- getClearCustomScriptCache: () => boolean;
82
- /** @deprecated Use `saveSetting("ClearCustomScriptCache", value)` instead */
83
- setClearCustomScriptCache: (value: boolean) => void;
84
80
  /** @deprecated Use `getSetting("RunCustomScripts")` instead */
85
81
  isCustomScriptsEnabled: () => boolean;
86
82
  /** @deprecated Use `getSetting("RunCustomScripts")` instead */
@@ -0,0 +1,6 @@
1
+ import type { ControlDeckControlType, EffectList } from "../../../types";
2
+ type ButtonParams = {
3
+ effects: EffectList;
4
+ };
5
+ export declare const buttonControlType: ControlDeckControlType<ButtonParams>;
6
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { ControlDeckControlType } from "../../../types";
2
+ type FolderParams = {
3
+ autoReturn: boolean;
4
+ };
5
+ export declare const folderControlType: ControlDeckControlType<FolderParams>;
6
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { ControlDeckControlType, EffectList } from "../../../types";
2
+ type SwitchParams = {
3
+ orientation: "horizontal" | "vertical";
4
+ color: string;
5
+ initialState: "restore" | "off" | "on";
6
+ runEffectsOnInit: boolean;
7
+ onEffects: EffectList;
8
+ offEffects: EffectList;
9
+ };
10
+ export declare const switchControlType: ControlDeckControlType<SwitchParams, boolean>;
11
+ export {};
@@ -5,7 +5,13 @@ declare class ControlDeckManager extends JsonDbManager<ControlDeck> {
5
5
  saveDeck(deck: ControlDeck, notify?: boolean): ControlDeck;
6
6
  deleteDeck(deckId: string): void;
7
7
  getControl(deckId: string, controlId: string): ControlDeckControl | null;
8
- triggerControl(deckId: string, controlId: string, inputValues?: Record<string, string | number | boolean>): boolean;
8
+ private buildTriggerEffectList;
9
+ /**
10
+ * Routes a hosted-page interaction to the control's type handler. Returns
11
+ * false when the control or its type can't be resolved.
12
+ */
13
+ handleInteraction(deckId: string, controlId: string, action: string, data: unknown, inputValues?: Record<string, string | number | boolean>): Promise<boolean>;
14
+ initializeControlStates(): Promise<void>;
9
15
  private broadcastToControlDecks;
10
16
  triggerUiRefresh(): void;
11
17
  }
@@ -0,0 +1,18 @@
1
+ import JsonDbManager from "../database/json-db-manager";
2
+ type ControlStateRecord = {
3
+ /** The control id. */
4
+ id: string;
5
+ state: unknown;
6
+ };
7
+ declare class ControlDeckStateManager extends JsonDbManager<ControlStateRecord> {
8
+ private stateLogger;
9
+ constructor();
10
+ getControlState(controlId: string): unknown;
11
+ setControlState(deckId: string, controlId: string, state: unknown, { broadcast }?: {
12
+ broadcast?: boolean;
13
+ }): void;
14
+ deleteControlState(controlId: string): void;
15
+ private broadcastToControlDecks;
16
+ }
17
+ declare const controlDeckStateManager: ControlDeckStateManager;
18
+ export { controlDeckStateManager as ControlDeckStateManager };
@@ -0,0 +1,13 @@
1
+ import type { ControlDeckControlType } from "../../types";
2
+ declare class ControlDeckControlTypeManager {
3
+ private logger;
4
+ private controlTypes;
5
+ constructor();
6
+ registerBuiltInControlTypes(): void;
7
+ private registerControlType;
8
+ getControlType(id: string): ControlDeckControlType<any, any> | null;
9
+ getAllControlTypes(): ControlDeckControlType<any, any>[];
10
+ private getControlTypesForFrontend;
11
+ }
12
+ declare const manager: ControlDeckControlTypeManager;
13
+ export { manager as ControlDeckControlTypeManager };
@@ -5,5 +5,8 @@ declare const effect: EffectType<{
5
5
  me: boolean;
6
6
  whisper: string;
7
7
  sendAsReply: boolean;
8
+ pin: boolean;
9
+ pinUntilEndOfStream: boolean;
10
+ pinDuration?: string;
8
11
  }>;
9
12
  export = effect;
@@ -1,4 +1,4 @@
1
- import { Notification, NotificationBase } from "../../types";
1
+ import type { Notification, NotificationBase } from "../../types";
2
2
  declare class NotificationManager {
3
3
  private logger;
4
4
  private _externalCheckInterval;
@@ -18,6 +18,7 @@ declare class NotificationManager {
18
18
  private loadExternalNotifications;
19
19
  startExternalNotificationCheck(): void;
20
20
  stopExternalNotificationCheck(): void;
21
+ migrateLegacyScriptNotifications(): void;
21
22
  }
22
23
  declare const manager: NotificationManager;
23
24
  export { manager as NotificationManager };
@@ -13,6 +13,10 @@ export interface PluginRegistrations {
13
13
  restrictionIds?: string[];
14
14
  integrationIds?: string[];
15
15
  gameIds?: string[];
16
+ frontendListeners?: Array<{
17
+ eventName: string;
18
+ id: string;
19
+ }>;
16
20
  uiExtensionIds?: string[];
17
21
  overlayWidgetIds?: string[];
18
22
  httpRoutePrefix?: string;
@@ -5,8 +5,6 @@ import JsonDbManager from "../database/json-db-manager";
5
5
  */
6
6
  declare class PluginConfigManager extends JsonDbManager<InstalledPluginConfig> {
7
7
  constructor();
8
- loadItems(): void;
9
- migrateLegacyStartUpScriptsToPlugins(): void;
10
8
  }
11
9
  declare const manager: PluginConfigManager;
12
10
  export { manager as PluginConfigManager };
@@ -17,6 +17,7 @@ declare class PluginManager {
17
17
  private pluginExecutors;
18
18
  private legacyEffectScriptExecutor;
19
19
  constructor();
20
+ migrateLegacyStartUpScriptsToPlugins(): Promise<void>;
20
21
  startPlugin(pluginConfig: InstalledPluginConfig, installing?: boolean): Promise<void>;
21
22
  private doStartPlugin;
22
23
  startPlugins(): Promise<void>;
@@ -1,3 +1,3 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<never>;
3
3
  export = model;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  type ComparisonType = "less" | "greater" | "equal";
3
3
  declare const model: RestrictionType<{
4
4
  selectedCurrency: string;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  gameId: string;
4
4
  name: string;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  messages: number;
4
4
  }>;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  name: string;
4
4
  value: string;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  checkMode: "streamer" | "custom";
4
4
  value: string;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  type RestrictionData = {
3
3
  perUserLimit?: number;
4
4
  globalLimit?: number;
@@ -1,3 +1,3 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const restriction: RestrictionType;
3
3
  export = restriction;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  type PermissionMode = "roles" | "viewer";
3
3
  type Rank = {
4
4
  rankId: string;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  mode: "time" | "days";
4
4
  days: string[];
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  declare const model: RestrictionType<{
3
3
  time: number;
4
4
  }>;
@@ -1,4 +1,4 @@
1
- import type { RestrictionType } from "../../../types/restrictions";
1
+ import type { RestrictionType } from "../../../types";
2
2
  type ComparisonType = "less" | "greater" | "equal";
3
3
  declare const model: RestrictionType<{
4
4
  comparison: ComparisonType;
@@ -1,6 +1,5 @@
1
1
  import { TypedEmitter } from "tiny-typed-emitter";
2
- import type { RestrictionData, RestrictionType } from "../../types/restrictions";
3
- import type { Trigger } from "../../types/triggers";
2
+ import type { RestrictionData, RestrictionResult, RestrictionType, Trigger } from "../../types";
4
3
  type Events = {
5
4
  "restriction-registered": (restriction: RestrictionType) => void;
6
5
  "restriction-unregistered": (restrictionId: string) => void;
@@ -15,7 +14,7 @@ declare class RestrictionsManager extends TypedEmitter<Events> {
15
14
  getAllRestrictions(): RestrictionType[];
16
15
  checkPermissionsPredicateOnly(restrictionData: RestrictionData, username: string, twitchRoles: string[]): Promise<boolean>;
17
16
  private runPredicate;
18
- runRestrictionPredicates(triggerData: Trigger, restrictionData: RestrictionData, restrictionsAreInherited?: boolean): Promise<void>;
17
+ runRestrictionPredicates(triggerData: Trigger, restrictionData: RestrictionData, restrictionsAreInherited?: boolean): Promise<RestrictionResult>;
19
18
  private mapRestrictionForFrontEnd;
20
19
  }
21
20
  declare const manager: RestrictionsManager;
@@ -35,6 +35,7 @@ declare class TwitchApi {
35
35
  get streamerClient(): ApiClient;
36
36
  get botClient(): ApiClient;
37
37
  get moderationClient(): ApiClient;
38
+ get moderatorId(): string;
38
39
  get accounts(): {
39
40
  streamer: FirebotAccount;
40
41
  bot: FirebotAccount;
@@ -7,6 +7,7 @@ export declare abstract class ApiResourceBase<T extends ListenerSignature<T> = u
7
7
  protected get streamerClient(): ApiClient;
8
8
  protected get botClient(): ApiClient;
9
9
  protected get moderationClient(): ApiClient;
10
+ protected get moderatorId(): string;
10
11
  protected get logger(): import("winston").Logger;
11
12
  protected get accounts(): {
12
13
  streamer: import("../../../../../types").FirebotAccount;
@@ -1,12 +1,33 @@
1
- import { HelixChatAnnouncementColor, HelixChatChatter, HelixUserEmote } from "@twurple/api";
2
- import type { SharedChatParticipant } from "../../../../../types";
3
- import { ApiResourceBase } from "./api-resource-base";
1
+ import type { HelixChatAnnouncementColor, HelixChatChatter, HelixUserEmote } from "@twurple/api";
2
+ import type { CamelCased, SharedChatParticipant } from "../../../../../types";
3
+ import type { EventSubChatMessageData } from "../twurple-private-types";
4
4
  import type { TwitchApi } from "../";
5
+ import { ApiResourceBase } from "./api-resource-base";
5
6
  interface ResultWithError<TResult, TError> {
6
7
  success: boolean;
7
8
  result?: TResult;
8
9
  error?: TError;
9
10
  }
11
+ interface SendChatMessageResult {
12
+ success: boolean;
13
+ isSlashCommand: boolean;
14
+ messageId?: string;
15
+ error?: string;
16
+ }
17
+ export type TwitchPinnedChatMessage = {
18
+ messageId: string;
19
+ broadcasterId: string;
20
+ senderUserId: string;
21
+ senderUserLogin: string;
22
+ senderUserName: string;
23
+ pinnedByUserId: string;
24
+ pinnedByUserLogin: string;
25
+ pinnedByUserName: string;
26
+ message: CamelCased<EventSubChatMessageData>;
27
+ startsAt: Date;
28
+ endsAt?: Date;
29
+ updatedAt: Date;
30
+ };
10
31
  export declare class TwitchChatApi extends ApiResourceBase {
11
32
  private _slashCommandHandler;
12
33
  constructor(apiBase: typeof TwitchApi);
@@ -21,9 +42,8 @@ export declare class TwitchChatApi extends ApiResourceBase {
21
42
  * @param replyToMessageId The ID of the message this should be replying to. Leave as null for non replies.
22
43
  * @param sendAsBot If the chat message should be sent as the bot or not.
23
44
  * If this is set to `false` or the bot account is not logged in, the chat message will be sent as the streamer.
24
- * @returns `true` if sending the chat message was successful or `false` if it failed
25
45
  */
26
- sendChatMessage(message: string, replyToMessageId?: string, sendAsBot?: boolean): Promise<boolean>;
46
+ sendChatMessage(message: string, replyToMessageId?: string, sendAsBot?: boolean): Promise<SendChatMessageResult>;
27
47
  /**
28
48
  * Sends an announcement to the streamer's chat.
29
49
  *
@@ -112,5 +132,30 @@ export declare class TwitchChatApi extends ApiResourceBase {
112
132
  * @returns An array of {@link SharedChatParticipant} containing all the participants in the shared chat session, or null if there is no active session
113
133
  */
114
134
  getSharedChatParticipants(): Promise<SharedChatParticipant[]>;
135
+ /**
136
+ * Gets the currently pinned message in the streamer's chat, if one exists
137
+ * @returns The currently pinned chat message, or `null` if no message is pinned
138
+ */
139
+ getPinnedChatMessage(): Promise<TwitchPinnedChatMessage>;
140
+ /**
141
+ * Pin a chat message to the top of the streamer's chat
142
+ * @param messageId ID of the chat message to pin
143
+ * @param duration The number of seconds the message should be pinned for. Minimum: 30. Maximum: 1800. If not specified, the message will be pinned until the stream ends.
144
+ * @returns `true` if the message was pinned, `false` if it failed
145
+ */
146
+ pinChatMessage(messageId: string, duration?: number): Promise<boolean>;
147
+ /**
148
+ * Updates the chat message currently pinned to the top of the streamer's chat
149
+ * @param messageId ID of the pinned message to update
150
+ * @param duration The number of seconds the message should be pinned for. Minimum: 30. Maximum: 1800. If not specified, the message will be pinned until the stream ends.
151
+ * @returns `true` if the pinned message was updated, `false` if it failed
152
+ */
153
+ updatePinnedChatMessage(messageId: string, duration?: number): Promise<boolean>;
154
+ /**
155
+ * Unpins a message from the streamer's chat
156
+ * @param messageId ID of the message to unpin
157
+ * @returns `true` if the message was unpinned, `false` if it failed
158
+ */
159
+ unpinChatMessage(messageId: string): Promise<boolean>;
115
160
  }
116
161
  export {};
@@ -0,0 +1,6 @@
1
+ import type { EffectType } from "../../../../types";
2
+ declare const effect: EffectType<{
3
+ pinUntilEndOfStream: boolean;
4
+ pinDuration?: string;
5
+ }>;
6
+ export = effect;
@@ -0,0 +1,3 @@
1
+ import type { EffectType } from "../../../../types";
2
+ declare const effect: EffectType;
3
+ export = effect;
@@ -0,0 +1,6 @@
1
+ import type { EffectType } from "../../../../types";
2
+ declare const effect: EffectType<{
3
+ pinUntilEndOfStream: boolean;
4
+ pinDuration?: string;
5
+ }>;
6
+ export = effect;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../../../../../types").ReplaceVariable[];
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
@@ -0,0 +1,3 @@
1
+ import type { ReplaceVariable } from "../../../../../../types";
2
+ declare const model: ReplaceVariable;
3
+ export default model;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowbartools/firebot-types",
3
- "version": "5.67.0-alpha20",
3
+ "version": "5.67.0-alpha21",
4
4
  "description": "Type definitions and plugin API for Firebot plugins.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,10 +1,9 @@
1
+ import type { FirebotParameterArray, FirebotParams, FontOptions } from "./parameters";
1
2
  import type { EffectList } from "./effects";
2
- /**
3
- * Reserved page id for the "Pinned" shadow page. Buttons with this pageId are
4
- * replicated onto every real page (unless a page button overrides the slot)
5
- */
3
+ import type { Awaitable } from "./util-types";
6
4
  export declare const CONTROL_DECK_PINNED_PAGE_ID = "pinned";
7
- export type ControlDeckControlType = "button" | "folder";
5
+ export declare const CONTROL_DECK_BUTTON_TYPE_ID = "firebot:button";
6
+ export declare const CONTROL_DECK_FOLDER_TYPE_ID = "firebot:folder";
8
7
  /** An image icon — either a local file path or a URL. */
9
8
  export type ControlDeckImageIcon = {
10
9
  type: "image";
@@ -21,16 +20,21 @@ export type ControlDeckGlyphIcon = {
21
20
  /** Optional CSS color; defaults to the control's text color */
22
21
  color?: string;
23
22
  };
24
- export type ControlDeckNoneIcon = {
25
- type: "none";
26
- };
27
23
  /** An emoji icon referenced by its unicode character. */
28
24
  export type ControlDeckEmojiIcon = {
29
25
  type: "emoji";
30
26
  /** The emoji character (eg "🔥") */
31
27
  emoji: string;
32
28
  };
33
- export type ControlDeckIcon = ControlDeckImageIcon | ControlDeckGlyphIcon | ControlDeckEmojiIcon | ControlDeckNoneIcon;
29
+ export type ControlDeckIcon = ControlDeckImageIcon | ControlDeckGlyphIcon | ControlDeckEmojiIcon;
30
+ export type ControlDeckBackground = {
31
+ type: "color";
32
+ color: string;
33
+ } | {
34
+ type: "image";
35
+ source: "local" | "url";
36
+ path: string;
37
+ };
34
38
  export type ControlDeckInputType = "text" | "number" | "toggle" | "preset";
35
39
  type ControlDeckInputBase = {
36
40
  /** Unique name of the input, used to access the value in effects */
@@ -64,33 +68,40 @@ export type ControlDeckControlSize = {
64
68
  /** Number of grid rows the control spans (default 1) */
65
69
  height: number;
66
70
  };
67
- export type ControlDeckControl = {
71
+ export type ControlDeckControl<Params extends FirebotParams = FirebotParams> = {
68
72
  id: string;
73
+ /** Reference name (shown in the editor, folder breadcrumbs, etc — not on the control itself) */
69
74
  name: string;
70
- type: ControlDeckControlType;
75
+ /** The control type id, e.g. "firebot:button" */
76
+ type: string;
77
+ /** Optional label rendered on the control itself, if the control type allows labels */
78
+ label?: string;
79
+ /** Font config for the label */
80
+ labelFont?: Partial<FontOptions>;
81
+ /** Label size as a percentage of the default size (100 = default) */
82
+ labelSize?: number;
71
83
  /** The page this control belongs to */
72
84
  pageId: string;
73
85
  /** The parent folder control id, or null when placed at the page root */
74
86
  parentId: string | null;
75
- /** The icon shown on the control */
76
- icon: ControlDeckIcon;
77
- backgroundColor?: string;
87
+ /** The icon shown on the control, if the control type allows icons */
88
+ icon?: ControlDeckIcon;
89
+ /** Icon size as a percentage of the default size (100 = default) */
90
+ iconSize?: number;
91
+ /** The background shown behind the control, if the control type allows backgrounds */
92
+ background?: ControlDeckBackground;
78
93
  /** Placement within the deck's grid */
79
94
  position?: ControlDeckControlPosition;
80
95
  /** How many grid cells the control spans (default 1x1) */
81
96
  size?: ControlDeckControlSize;
82
- /** Effects to run when the control is pressed. Only used when type is "button" */
83
- effectList?: EffectList;
84
97
  /**
85
- * Inputs the user is prompted for when the control is pressed on the hosted
86
- * page. The provided values are sent with the press and are available to
87
- * effects via $controlDeckInput
98
+ * Inputs the user is prompted for when the control is interacted with on the
99
+ * hosted page. The provided values are sent with the interaction and are
100
+ * available to effects via $controlDeckInput
88
101
  */
89
102
  inputs?: ControlDeckControlInput[];
90
- /**
91
- * Whether a folder control should automatically return to the parent page after a button within it is pressed. Only used when type is "folder".
92
- */
93
- autoReturn?: boolean;
103
+ /** Type-specific settings, defined by the control type's settingsSchema */
104
+ settings: Params;
94
105
  };
95
106
  export type ControlDeckGrid = {
96
107
  cols: number;
@@ -116,7 +127,7 @@ export type ControlDeckSettings = {
116
127
  /**
117
128
  * How the hosted grid responds to device rotation.
118
129
  * - "fixed": grid keeps its designed dimensions regardless of orientation
119
- * - "dynamic": grid rotates to best fill the screen for the current orientation
130
+ * - "dynamic": grid rotates to best fill the screen
120
131
  */
121
132
  orientationMode?: ControlDeckOrientationMode;
122
133
  };
@@ -131,16 +142,95 @@ export type ControlDeckResolvedIcon = {
131
142
  type: "emoji";
132
143
  emoji: string;
133
144
  };
134
- /**
135
- * A control as projected to the hosted Control Deck page. Server-only fields
136
- * (the raw effect list and local icon path) are removed, and the resolved
137
- * `icon` the page should render is added.
138
- */
139
- export type ControlDeckControlView = Omit<ControlDeckControl, "icon" | "effectList"> & {
145
+ /** A control background as projected to the hosted page (local images resolved to urls) */
146
+ export type ControlDeckResolvedBackground = {
147
+ type: "color";
148
+ color: string;
149
+ } | {
150
+ type: "image";
151
+ url: string;
152
+ };
153
+ export type ControlDeckControlView = Omit<ControlDeckControl, "icon" | "background" | "settings"> & {
140
154
  icon?: ControlDeckResolvedIcon;
155
+ background?: ControlDeckResolvedBackground;
156
+ resolvedSettings: Record<string, unknown>;
157
+ /** Current runtime state for stateful control types (e.g. a Switch's on/off value) */
158
+ state?: unknown;
159
+ shell: "standard" | "none";
141
160
  };
142
161
  /** A deck as projected to the hosted Control Deck page. */
143
162
  export type ControlDeckView = Omit<ControlDeck, "controls"> & {
144
163
  controls: ControlDeckControlView[];
145
164
  };
165
+ /** The event passed to a control type's onInteraction handler */
166
+ export type ControlDeckInteractionEvent<Params extends FirebotParams = FirebotParams> = {
167
+ control: ControlDeckControl<Params>;
168
+ deckId: string;
169
+ action: string;
170
+ data: unknown;
171
+ /** Values the user provided for the control's configured inputs */
172
+ inputValues: Record<string, string | number | boolean>;
173
+ };
174
+ export type ControlDeckInteractionContext<State = unknown> = {
175
+ /**
176
+ * Runs an effect list with the standard control_deck trigger metadata.
177
+ * metadata is merged into the trigger metadata.
178
+ */
179
+ triggerEffectList: (effectList: EffectList, extraMetadata?: Record<string, unknown>) => Promise<void>;
180
+ /** The control's current runtime state (stateful types only) */
181
+ getState: () => State;
182
+ /**
183
+ * Sets the control's runtime state. The central store persists it and
184
+ * broadcasts the change to connected devices.
185
+ */
186
+ setState: (newState: State) => Promise<void>;
187
+ };
188
+ /** Context provided when a stateful control type computes its initial state */
189
+ export type ControlDeckStateInitContext = {
190
+ triggerEffectList: (effectList: EffectList, extraMetadata?: Record<string, unknown>) => Promise<void>;
191
+ };
192
+ export type ControlDeckControlTypeState<Params extends FirebotParams = FirebotParams, State = unknown> = {
193
+ /**
194
+ * Called on Firebot startup (and when a control is first added) to compute
195
+ * the state the control should initialize to
196
+ */
197
+ getInitialState: (event: {
198
+ control: ControlDeckControl<Params>;
199
+ persistedState: State | undefined;
200
+ }, context: ControlDeckStateInitContext) => Awaitable<State>;
201
+ };
202
+ export type ControlDeckControlType<Params extends FirebotParams = FirebotParams, State = void> = {
203
+ id: string;
204
+ /** Display name shown in the Add Control picker, e.g. "Slider" */
205
+ name: string;
206
+ description: string;
207
+ /** Font Awesome icon class for the Add Control picker, e.g. "fa-square" */
208
+ icon: string;
209
+ /** Default grid cell span when the control is added */
210
+ defaultSize?: ControlDeckControlSize;
211
+ minSize?: ControlDeckControlSize;
212
+ maxSize?: ControlDeckControlSize;
213
+ /** When false, the control cannot be resized in the editor. Defaults to true. */
214
+ resizable?: boolean;
215
+ /** When true, the standard icon config is shown for controls of this type */
216
+ enableIcon?: boolean;
217
+ /**
218
+ * Default icon for new controls of this type.
219
+ */
220
+ defaultIcon?: ControlDeckIcon;
221
+ /** When true, the standard background config (color or image) is shown for controls of this type */
222
+ enableBackground?: boolean;
223
+ /** When true, the inputs config is shown for controls of this type */
224
+ enableInputs?: boolean;
225
+ /** When true, the optional label (+ label font) config is shown for controls of this type */
226
+ enableLabel?: boolean;
227
+ /** The shell style for the control. "standard" uses the default shell and click animation, "none" removes it. */
228
+ shell?: "standard" | "none";
229
+ /** Schema for the type-specific settings shown in the control edit modal */
230
+ settingsSchema: FirebotParameterArray<Params>;
231
+ /** Declares this control type as stateful. */
232
+ state?: ControlDeckControlTypeState<Params, State>;
233
+ /** Called when a device interacts with a control of this type */
234
+ onInteraction: (event: ControlDeckInteractionEvent<Params>, context: ControlDeckInteractionContext<State>) => Awaitable<void>;
235
+ };
146
236
  export {};
@@ -38,6 +38,7 @@ export type PasswordParameter = BaseParameter & {
38
38
  };
39
39
  export type BooleanParameter = BaseParameter & {
40
40
  type: "boolean";
41
+ useSwitch?: boolean;
41
42
  default: boolean;
42
43
  };
43
44
  export type NumberParameter = BaseParameter & {
@@ -180,6 +181,8 @@ export type FontOptionsParameter = BaseParameter & {
180
181
  default: FontOptions;
181
182
  allowAlpha?: boolean;
182
183
  hideColor?: boolean;
184
+ /** When true, the font size input is hidden */
185
+ hideSize?: boolean;
183
186
  };
184
187
  export type RadioCardsParameter<V = string> = BaseParameter & {
185
188
  type: "radio-cards";
@@ -105,16 +105,6 @@ export interface PluginFrontendCommunicatorApi {
105
105
  * back.
106
106
  */
107
107
  fireEventAsync<ReturnPayload = void, ExpectedArg = unknown>(eventName: string, data?: ExpectedArg): Promise<ReturnPayload>;
108
- /**
109
- * Handle a synchronous event triggered by the frontend. Returns an
110
- * `unsubscribe` function.
111
- */
112
- on<ExpectedArgs extends Array<unknown> = [], ReturnPayload = void>(eventName: string, callback: (...args: ExpectedArgs) => ReturnPayload): () => void;
113
- /**
114
- * Handle an asynchronous event triggered by the frontend. Returns an
115
- * `unsubscribe` function.
116
- */
117
- onAsync<ExpectedArgs extends Array<unknown> = [], ReturnPayload = void>(eventName: string, callback: (...args: ExpectedArgs) => Promise<ReturnPayload>): () => void;
118
108
  }
119
109
  export interface PluginSettingsApi {
120
110
  /**
@@ -8,7 +8,7 @@ import type { RestrictionType } from "./restrictions";
8
8
  import type { FirebotParams, FirebotParameterArray } from "./parameters";
9
9
  import type { FirebotGame } from "./games";
10
10
  import type { Integration } from "./integrations";
11
- import type { UIExtension } from "./ui-extensions";
11
+ import type { FrontendListener, UIExtension } from "./ui-extensions";
12
12
  import type { OverlayWidgetType } from "./overlay-widgets";
13
13
  import type { PluginHttpRouteDefinition } from "./http-server";
14
14
  import type { CustomWebSocketHandler } from "./websocket";
@@ -114,6 +114,7 @@ export interface Plugin<Params extends FirebotParams = FirebotParams> extends Pl
114
114
  restrictions?: DynamicArray<RestrictionType<any>>;
115
115
  systemCommands?: DynamicArray<SystemCommand<any>>;
116
116
  games?: DynamicArray<FirebotGame>;
117
+ frontendListeners?: DynamicArray<FrontendListener>;
117
118
  uiExtensions?: DynamicArray<UIExtension>;
118
119
  overlayWidgets?: DynamicArray<OverlayWidgetType<any, any>>;
119
120
  httpRoutes?: DynamicObject<PluginHttpRouteDefinition>;
@@ -8,6 +8,10 @@ interface RestrictionScope<RestrictionModel> extends ng.IScope {
8
8
  [x: string]: any;
9
9
  }
10
10
  export type RestrictionMode = "all" | "any" | "none";
11
+ export type RestrictionResult = {
12
+ success: boolean;
13
+ failureReason?: string;
14
+ };
11
15
  export type RestrictionType<RestrictionModel = unknown> = {
12
16
  definition: {
13
17
  id: string;
@@ -19,7 +23,7 @@ export type RestrictionType<RestrictionModel = unknown> = {
19
23
  optionsTemplate: string;
20
24
  optionsController?: ($scope: RestrictionScope<RestrictionModel>, ...args: any[]) => void;
21
25
  optionsValueDisplay?: (restriction: RestrictionModel, ...args: any[]) => string;
22
- predicate(triggerData: Trigger, restrictionData: RestrictionModel, inherited?: boolean): Awaitable<boolean>;
26
+ predicate(triggerData: Trigger, restrictionData: RestrictionModel, inherited?: boolean): Awaitable<RestrictionResult>;
23
27
  onSuccessful?: (triggerData: Trigger, restrictionData: RestrictionModel, inherited?: boolean) => Awaitable<void>;
24
28
  };
25
29
  export type Restriction<RestrictionModel = unknown> = {
@@ -55,7 +55,6 @@ export type FirebotSettingsTypes = {
55
55
  ChatTaggedNotificationVolume: number;
56
56
  ChatTimestamps: boolean;
57
57
  ClearChatFeedMode: "never" | "onlyStreamer" | "always";
58
- ClearCustomScriptCache: boolean;
59
58
  ConnectOnLaunch: boolean;
60
59
  ControlDeckEnabled: boolean;
61
60
  ControlDeckPin?: string;
@@ -0,0 +1,8 @@
1
+ export type ControlDeckService = {
2
+ getControlType: (typeId: string) => {
3
+ settingsSchema?: Array<{
4
+ name: string;
5
+ type?: string;
6
+ }>;
7
+ } | null;
8
+ };
@@ -10,3 +10,4 @@ export * from "./firebot-root-scope";
10
10
  export * from "./object-copy-helper";
11
11
  export * from "./preset-effect-lists-service";
12
12
  export * from "./effect-queues-service";
13
+ export * from "./control-deck-service";
@@ -94,3 +94,8 @@ export type UIExtension = {
94
94
  parameters?: AngularJsFirebotParameterComponent[];
95
95
  };
96
96
  };
97
+ export type FrontendListener = {
98
+ eventName: string;
99
+ useAsync?: boolean;
100
+ handler: <ExpectedArgs extends Array<unknown> = [], ReturnPayload = void>(...args: ExpectedArgs) => ReturnPayload;
101
+ };
@@ -23,4 +23,8 @@ type CamelToSnake<S extends string, Acc extends string = ""> = S extends `${infe
23
23
  export type SnakeCased<T> = T extends Date ? string : T extends Array<infer U> ? Array<SnakeCased<U>> : T extends object ? {
24
24
  [K in keyof T as K extends string ? CamelToSnake<K> : K]: SnakeCased<T[K]>;
25
25
  } : T;
26
+ type SnakeToCamel<S extends string> = S extends `${infer H}_${infer T}` ? `${H}${Capitalize<SnakeToCamel<T>>}` : S;
27
+ export type CamelCased<T> = T extends Date ? string : T extends Array<infer U> ? Array<CamelCased<U>> : T extends object ? {
28
+ [K in keyof T as K extends string ? SnakeToCamel<K> : K]: CamelCased<T[K]>;
29
+ } : T;
26
30
  export {};
File without changes