import * as tg from "generic-type-guard"; import type { GameStateEvent } from "./GameStateEvent"; import type { ButtonClickedEvent } from "./ButtonClickedEvent"; import type { ChatEvent } from "./ChatEvent"; import type { ClosePopupEvent } from "./ClosePopupEvent"; import type { EnterLeaveEvent } from "./EnterLeaveEvent"; import type { GoToPageEvent } from "./GoToPageEvent"; import type { LoadPageEvent } from "./LoadPageEvent"; import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent"; import type { OpenPopupEvent } from "./OpenPopupEvent"; import type { OpenTabEvent } from "./OpenTabEvent"; import type { UserInputChatEvent } from "./UserInputChatEvent"; import type { MapDataEvent } from "./MapDataEvent"; import type { LayerEvent } from "./LayerEvent"; import type { SetPropertyEvent } from "./setPropertyEvent"; import type { LoadSoundEvent } from "./LoadSoundEvent"; import type { PlaySoundEvent } from "./PlaySoundEvent"; import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent"; import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent"; import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent"; import type { SetTilesEvent } from "./SetTilesEvent"; import type { SetVariableEvent } from "./SetVariableEvent"; import {isGameStateEvent} from "./GameStateEvent"; import {isMapDataEvent} from "./MapDataEvent"; import {isSetVariableEvent} from "./SetVariableEvent"; export interface TypedMessageEvent extends MessageEvent { data: T; } /** * List event types sent from an iFrame to WorkAdventure */ export type IframeEventMap = { loadPage: LoadPageEvent; chat: ChatEvent; openPopup: OpenPopupEvent; closePopup: ClosePopupEvent; openTab: OpenTabEvent; goToPage: GoToPageEvent; openCoWebSite: OpenCoWebSiteEvent; closeCoWebSite: null; disablePlayerControls: null; restorePlayerControls: null; displayBubble: null; removeBubble: null; onPlayerMove: undefined; showLayer: LayerEvent; hideLayer: LayerEvent; setProperty: SetPropertyEvent; loadSound: LoadSoundEvent; playSound: PlaySoundEvent; stopSound: null; getState: undefined; registerMenuCommand: MenuItemRegisterEvent; setTiles: SetTilesEvent; }; export interface IframeEvent { type: T; data: IframeEventMap[T]; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeEventWrapper = (event: any): event is IframeEvent => typeof event.type === "string"; export interface IframeResponseEventMap { userInputChat: UserInputChatEvent; enterEvent: EnterLeaveEvent; leaveEvent: EnterLeaveEvent; buttonClickedEvent: ButtonClickedEvent; hasPlayerMoved: HasPlayerMovedEvent; menuItemClicked: MenuItemClickedEvent; setVariable: SetVariableEvent; } export interface IframeResponseEvent { type: T; data: IframeResponseEventMap[T]; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeResponseEventWrapper = (event: { type?: string; }): event is IframeResponseEvent => typeof event.type === "string"; /** * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame. * Types are defined using Type guards that will actually bused to enforce and check types. */ export const iframeQueryMapTypeGuards = { getState: { query: tg.isUndefined, answer: isGameStateEvent, }, getMapData: { query: tg.isUndefined, answer: isMapDataEvent, }, setVariable: { query: isSetVariableEvent, answer: tg.isUndefined, }, } type GuardedType = T extends (x: unknown) => x is (infer T) ? T : never; type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards; type UnknownToVoid = undefined extends T ? void : T; export type IframeQueryMap = { [key in keyof IframeQueryMapTypeGuardsType]: { query: GuardedType answer: UnknownToVoid> } } export interface IframeQuery { type: T; data: IframeQueryMap[T]['query']; } export interface IframeQueryWrapper { id: number; query: IframeQuery; } export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => { return type in iframeQueryMapTypeGuards; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeQuery = (event: any): event is IframeQuery => { const type = event.type; if (typeof type !== 'string') { return false; } if (!isIframeQueryKey(type)) { return false; } return iframeQueryMapTypeGuards[type].query(event.data); } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper => typeof event.id === 'number' && isIframeQuery(event.query); export interface IframeAnswerEvent { id: number; type: T; data: IframeQueryMap[T]['answer']; } export const isIframeAnswerEvent = (event: { type?: string, id?: number }): event is IframeAnswerEvent => typeof event.type === 'string' && typeof event.id === 'number'; export interface IframeErrorAnswerEvent { id: number; type: keyof IframeQueryMap; error: string; } export const isIframeErrorAnswerEvent = (event: { type?: string, id?: number, error?: string }): event is IframeErrorAnswerEvent => typeof event.type === 'string' && typeof event.id === 'number' && typeof event.error === 'string';