From 7303da3991814a0ce220bf2fff3e51b968913b86 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 29 Dec 2023 19:17:46 -0500 Subject: Cross frame API safety (#491) * Require error type * Add TODOs * Fix init * Updates * More type safety * Fix incorrect API map * Update type safety * Updates * Add API * Update types * Update types * Updates * Remove unused * Restore types * Update frame ancestry handler * Simplify names * Fix * Remove old message handlers --- types/ext/core.d.ts | 13 -- types/ext/cross-frame-api.d.ts | 215 ++++++++++++++++++++++++++++++++-- types/ext/display.d.ts | 14 ++- types/ext/frame-ancestry-handler.d.ts | 7 +- types/ext/frontend.d.ts | 4 - 5 files changed, 219 insertions(+), 34 deletions(-) (limited to 'types/ext') diff --git a/types/ext/core.d.ts b/types/ext/core.d.ts index b94b649b..48cb68d3 100644 --- a/types/ext/core.d.ts +++ b/types/ext/core.d.ts @@ -74,19 +74,6 @@ export type ResponseError = { export type Response = ResponseSuccess | ResponseError; -export type MessageHandler = (params: SafeAny, ...extraArgs: SafeAny[]) => ( - MessageHandlerResult | - Promise -); - -export type MessageHandlerResult = SafeAny; - -export type MessageHandlerMap = Map; - -export type MessageHandlerMapInit = MessageHandlerMapInitItem[]; - -export type MessageHandlerMapInitItem = [key: string, handlerDetails: MessageHandler]; - export type Timeout = number | NodeJS.Timeout; export type EventSurface = {[name: string]: unknown}; diff --git a/types/ext/cross-frame-api.d.ts b/types/ext/cross-frame-api.d.ts index 8ddca6e7..148bfe00 100644 --- a/types/ext/cross-frame-api.d.ts +++ b/types/ext/cross-frame-api.d.ts @@ -16,7 +16,28 @@ */ import type {CrossFrameAPIPort} from '../../ext/js/comm/cross-frame-api.js'; -import type * as Core from './core'; +import type {Response, Timeout, TokenString} from './core'; +import type {ModifierKey} from './input'; +import type {ContentDetails as PopupContentDetails, ValidSize} from './popup'; +import type {GetOrCreatePopupDetails} from './popup-factory'; +import type {OptionsContext} from './settings'; +import type { + ApiMap as BaseApiMap, + ApiParams as BaseApiParams, + ApiNames as BaseApiNames, + ApiMapInit as BaseApiMapInit, + ApiHandler as BaseApiHandler, + ApiReturn as BaseApiReturn, + ApiReturnAny as BaseApiReturnAny, +} from './api-map'; +import type { + DirectApiFrameClientMessageAny as DisplayDirectApiFrameClientMessageAny, + DirectApiMessageAny as DisplayDirectApiMessageAny, + DirectApiReturnAny as DisplayDirectApiReturnAny, + ContentDetails as DisplayContentDetails, +} from './display'; +import type {ChildFrameRect} from 'frame-offset-forwarder'; +import type {RequestFrameInfoResponseParams, RequestFrameInfoResponseReturn} from './frame-ancestry-handler'; export type CrossFrameAPIPortEvents = { disconnect: CrossFrameAPIPort; @@ -30,30 +51,25 @@ export type AcknowledgeMessage = { export type ResultMessage = { type: 'result'; id: number; - data: Core.Response; + data: Response; }; export type InvokeMessage = { type: 'invoke'; id: number; - data: InvocationData; -}; - -export type InvocationData = { - action: string; - params: Core.SerializableObject; + data: ApiMessageAny; }; export type Message = AcknowledgeMessage | ResultMessage | InvokeMessage; export type Invocation = { id: number; - resolve: (value: Core.SafeAny) => void; - reject: (reason?: unknown) => void; + resolve: (value: ApiReturnAny) => void; + reject: (reason: Error) => void; responseTimeout: number; action: string; ack: boolean; - timer: Core.Timeout | null; + timer: Timeout | null; }; export type PortDetails = CrossFrameCommunicationPortDetails; @@ -63,3 +79,180 @@ export type CrossFrameCommunicationPortDetails = { otherTabId: number; otherFrameId: number; }; + +type ApiSurface = { + displayPopupMessage1: { + params: DisplayDirectApiFrameClientMessageAny; + return: DisplayDirectApiReturnAny; + }; + displayPopupMessage2: { + params: DisplayDirectApiMessageAny; + return: DisplayDirectApiReturnAny; + }; + frontendClosePopup: { + params: void; + return: void; + }; + frontendCopySelection: { + params: void; + return: void; + }; + frontendGetSelectionText: { + params: void; + return: string; + }; + frontendGetPopupInfo: { + params: void; + return: { + popupId: string | null; + }; + }; + frontendGetPageInfo: { + params: void; + return: { + url: string; + documentTitle: string; + }; + }; + frameOffsetForwarderGetChildFrameRect: { + params: { + frameId: number; + }; + return: ChildFrameRect | null; + }; + hotkeyHandlerForwardHotkey: { + params: { + key: string; + modifiers: ModifierKey[]; + }; + return: boolean; + }; + popupFactoryGetOrCreatePopup: { + params: GetOrCreatePopupDetails; + return: {id: string, depth: number, frameId: number}; + }; + popupFactorySetOptionsContext: { + params: { + id: string; + optionsContext: OptionsContext; + }; + return: void; + }; + popupFactoryHide: { + params: { + id: string; + changeFocus: boolean; + }; + return: void; + }; + popupFactoryIsVisible: { + params: { + id: string; + }; + return: boolean; + }; + popupFactorySetVisibleOverride: { + params: { + id: string; + value: boolean; + priority: number; + }; + return: TokenString | null; + }; + popupFactoryClearVisibleOverride: { + params: { + id: string; + token: TokenString; + }; + return: boolean; + }; + popupFactoryContainsPoint: { + params: { + id: string; + x: number; + y: number; + }; + return: boolean; + }; + popupFactoryShowContent: { + params: { + id: string; + details: PopupContentDetails; + displayDetails: DisplayContentDetails | null; + }; + return: void; + }; + popupFactorySetCustomCss: { + params: { + id: string; + css: string; + }; + return: void; + }; + popupFactoryClearAutoPlayTimer: { + params: { + id: string; + }; + return: void; + }; + popupFactorySetContentScale: { + params: { + id: string; + scale: number; + }; + return: void; + }; + popupFactoryUpdateTheme: { + params: { + id: string; + }; + return: void; + }; + popupFactorySetCustomOuterCss: { + params: { + id: string; + css: string; + useWebExtensionApi: boolean; + }; + return: void; + }; + popupFactoryGetFrameSize: { + params: { + id: string; + }; + return: ValidSize; + }; + popupFactorySetFrameSize: { + params: { + id: string; + width: number; + height: number; + }; + return: boolean; + }; + frameAncestryHandlerRequestFrameInfoResponse: { + params: RequestFrameInfoResponseParams; + return: RequestFrameInfoResponseReturn; + }; +}; + +export type ApiNames = BaseApiNames; + +export type ApiMapInit = BaseApiMapInit; + +export type ApiMap = BaseApiMap; + +export type ApiHandler = BaseApiHandler; + +export type ApiParams = BaseApiParams; + +export type ApiReturn = BaseApiReturn; + +export type ApiReturnAny = BaseApiReturnAny; + +export type ApiMessageAny = {[name in ApiNames]: ApiMessage}[ApiNames]; + +type ApiMessage = { + action: TName; + params: ApiParams; +}; diff --git a/types/ext/display.d.ts b/types/ext/display.d.ts index f7c45b02..127823d2 100644 --- a/types/ext/display.d.ts +++ b/types/ext/display.d.ts @@ -23,6 +23,7 @@ import type * as Extension from './extension'; import type * as Settings from './settings'; import type * as TextScannerTypes from './text-scanner'; import type {EventNames, EventArgument as BaseEventArgument} from './core'; +import type {Message as FrameClientMessage} from './frame-client'; import type { ApiMap as BaseApiMap, ApiParams as BaseApiParams, @@ -30,6 +31,7 @@ import type { ApiMapInit as BaseApiMapInit, ApiParamsAny as BaseApiParamsAny, ApiHandler as BaseApiHandler, + ApiReturn as BaseApiReturn, } from './api-map'; export type HistoryMode = 'clear' | 'overwrite' | 'new'; @@ -222,7 +224,7 @@ export type DirectApiSurface = { }; }; -type DirectApiNames = BaseApiNames; +export type DirectApiNames = BaseApiNames; export type DirectApiMapInit = BaseApiMapInit; @@ -230,7 +232,9 @@ export type DirectApiMap = BaseApiMap; export type DirectApiHandler = BaseApiHandler; -type DirectApiParams = BaseApiParams; +export type DirectApiParams = BaseApiParams; + +export type DirectApiReturn = BaseApiReturn; export type DirectApiMessageAny = {[name in DirectApiNames]: DirectApiMessage}[DirectApiNames]; @@ -241,10 +245,12 @@ type DirectApiMessage = { params: DirectApiParams; }; +export type DirectApiFrameClientMessageAny = {[name in DirectApiNames]: FrameClientMessage>}[DirectApiNames]; + // Window API export type WindowApiSurface = { - 'displayExtensionUnloaded': { + displayExtensionUnloaded: { params: void; return: void; }; @@ -266,3 +272,5 @@ type WindowApiMessage = { action: TName; params: WindowApiParams; }; + +export type WindowApiFrameClientMessageAny = {[name in WindowApiNames]: FrameClientMessage>}[WindowApiNames]; \ No newline at end of file diff --git a/types/ext/frame-ancestry-handler.d.ts b/types/ext/frame-ancestry-handler.d.ts index 3c9e32bf..4eb7f861 100644 --- a/types/ext/frame-ancestry-handler.d.ts +++ b/types/ext/frame-ancestry-handler.d.ts @@ -16,11 +16,12 @@ */ export type RequestFrameInfoResponseParams = { + uniqueId: string; frameId: number; nonce: string; more: boolean; }; -export type RequestFrameInfoResponseReturn = { - nonce: string; -}; +export type RequestFrameInfoResponseReturn = {nonce: string} | null; + +export type ResponseHandler = (params: RequestFrameInfoResponseParams) => RequestFrameInfoResponseReturn; diff --git a/types/ext/frontend.d.ts b/types/ext/frontend.d.ts index 4cc8d03b..b06e6040 100644 --- a/types/ext/frontend.d.ts +++ b/types/ext/frontend.d.ts @@ -47,7 +47,3 @@ export type ConstructorDetails = { }; export type PageType = 'web' | 'popup' | 'search'; - -export type GetPopupInfoResult = { - popupId: string | null; -}; -- cgit v1.2.3