import { type Asyncify, type ValueOf } from "type-fest"; import { type ErrorObject } from "serialize-error"; /** * @file Target types are a bit overlapping. That's because some are "request" targets * and some are "known" targets. The difference is that you could "request" `{tabId: 1}`, but you "know" that a specific target is exactly `{tabId: 1, frameId: 5}` * TODO: Cleanup, clarify, deduplicate Target types */ declare global { interface MessengerMethods { _: Method; } } type WithTarget = Method extends (...args: infer PreviousArguments) => infer TReturnValue ? (target: AnyTarget, ...args: PreviousArguments) => TReturnValue : never; type ActuallyOmitThisParameter = T extends (...args: infer A) => infer R ? (...args: A) => R : T; /** Removes the `this` type and ensure it's always Promised */ export type PublicMethod> = Asyncify>; export type PublicMethodWithTarget> = WithTarget>; export interface MessengerMeta { trace: Sender[]; } type RawMessengerResponse = { value: unknown; } | { error: ErrorObject; }; export type MessengerResponse = RawMessengerResponse & { /** Guarantees that the message was handled by this library */ __webextMessenger: true; }; type Arguments = unknown[]; export type Method = (this: MessengerMeta, ...args: Arguments) => Promise; export interface Options { /** * "Notifications" won't await the response, return values, attempt retries, nor throw errors * @default false */ isNotification?: boolean; trace?: Sender[]; retry?: boolean; /** Automatically generated internally */ seq?: number; } export type Message = { type: keyof MessengerMethods; args: LocalArguments; target: AnyTarget; /** If the message is being sent to an intermediary receiver, also set the options */ options?: Options; }; export type ExternalMessage = Message & { target: ExtensionTarget; }; export type Sender = chrome.runtime.MessageSender; export type MessengerMessage = Message & { /** Guarantees that a message is meant to be handled by this library */ __webextMessenger: true; }; /** A loose union to simplify the internal checks. */ export interface LooseTarget { tabId?: number | "this"; frameId?: number | "allFrames"; page?: string; extensionId?: string; } export interface TopLevelFrame { tabId: number; frameId: 0; } export interface FrameTarget { tabId: number; frameId: number; } export interface KnownTarget { tabId?: number; frameId?: number; page: string; } export interface Target { tabId: number; frameId?: number | "allFrames"; } export interface PageTarget { tabId?: number | "this"; page: string; } export interface ExtensionTarget { extensionId: string; } export type AnyTarget = Target | PageTarget | ExtensionTarget; export {};