diff --git a/api/messaging/src/index.ts b/api/messaging/src/index.ts index 44ee33776..fa0dca143 100644 --- a/api/messaging/src/index.ts +++ b/api/messaging/src/index.ts @@ -47,7 +47,10 @@ export const sendToActiveContentScript = sendToContentScript * Any request sent to this relay get send to background, then emitted back as a response */ export const relayMessage: PlasmoMessaging.MessageRelayFx = (req) => - rawRelay(req, sendToBackground) + rawRelay( + req, + sendToBackground as (req: PlasmoMessaging.Request) => Promise + ) /** * @deprecated Migrated to `relayMessage` diff --git a/api/messaging/src/types.ts b/api/messaging/src/types.ts index 1eec6b713..b437692e9 100644 --- a/api/messaging/src/types.ts +++ b/api/messaging/src/types.ts @@ -62,15 +62,28 @@ export namespace PlasmoMessaging { > export interface SendFx { - ( - request: Request, + ( + request: Request< + TSpecificName, + TSpecificName extends keyof MessagesMetadata + ? MessagesMetadata[TSpecificName] extends { req: infer R } + ? R + : any + : any + >, messagePort?: | Pick< MessagePort, "addEventListener" | "removeEventListener" | "postMessage" > | Window - ): Promise + ): Promise< + TSpecificName extends keyof MessagesMetadata + ? MessagesMetadata[TSpecificName] extends { res: infer R } + ? R + : any + : any + > } export interface RelayFx { @@ -93,12 +106,28 @@ export namespace PlasmoMessaging { } export interface PortHook { - , TResponseBody = any>( - name: PortName + ( + name: TName ): { - data?: TResponseBody - send: (payload: TRequestBody) => void - listen: ( + data?: TName extends keyof PortsMetadata + ? PortsMetadata[TName] extends { res: infer R } + ? R + : any + : any + send: ( + payload: TName extends keyof PortsMetadata + ? PortsMetadata[TName] extends { req: infer R } + ? R + : any + : any + ) => void + listen: < + T = TName extends keyof PortsMetadata + ? PortsMetadata[TName] extends { res: infer R } + ? R + : any + : any + >( handler: (msg: T) => void ) => { port: chrome.runtime.Port diff --git a/cli/plasmo/src/features/background-service-worker/bgsw-messaging.ts b/cli/plasmo/src/features/background-service-worker/bgsw-messaging.ts index e44cf2d5b..ff7849c12 100644 --- a/cli/plasmo/src/features/background-service-worker/bgsw-messaging.ts +++ b/cli/plasmo/src/features/background-service-worker/bgsw-messaging.ts @@ -1,7 +1,7 @@ +import { join, resolve } from "path" import { camelCase } from "change-case" import glob from "fast-glob" -import { outputFile } from "fs-extra" -import { join, resolve } from "path" +import { outputFile, readFile } from "fs-extra" import { isWriteable } from "@plasmo/utils/fs" import { vLog, wLog } from "@plasmo/utils/logging" @@ -81,19 +81,37 @@ const getHandlerList = async ( ignore: dirName === "messages" ? ["external"] : [] }) - return handlerFileList.map((filePath) => { - const posixFilePath = toPosix(filePath) - const handlerName = posixFilePath.slice(0, -3) - const importPath = `${dirName}/${handlerName}` - const importName = camelCase(importPath) - - return { - importName, - name: handlerName, - declaration: `"${handlerName}" : {}`, - importCode: `import { default as ${importName} } from "~background/${importPath}"` - } - }) + return Promise.all( + handlerFileList.map(async (filePath) => { + const posixFilePath = toPosix(filePath) + const handlerName = posixFilePath.slice(0, -3) + const importPath = `${dirName}/${handlerName}` + const importName = camelCase(importPath) + + const source = await readFile(join(handlerDir, filePath), "utf8") + const hasReqBody = /export\s+(?:type|interface)\s+RequestBody\b/.test( + source + ) + const hasResBody = /export\s+(?:type|interface)\s+ResponseBody\b/.test( + source + ) + + const typeRef = `~background/${importPath}` + const bodyTypes = [ + hasReqBody ? `req: import("${typeRef}").RequestBody` : null, + hasResBody ? `res: import("${typeRef}").ResponseBody` : null + ] + .filter(Boolean) + .join(", ") + + return { + importName, + name: handlerName, + declaration: `"${handlerName}" : { ${bodyTypes} }`, + importCode: `import { default as ${importName} } from "~background/${importPath}"` + } + }) + ) } const getMessageCode = (name: string, importName: string) => `case "${name}":