diff --git a/packages/messaging/src/custom-event.ts b/packages/messaging/src/custom-event.ts index c462ee7..20e31d8 100644 --- a/packages/messaging/src/custom-event.ts +++ b/packages/messaging/src/custom-event.ts @@ -1,6 +1,7 @@ import { uid } from 'uid'; import { GenericMessenger, defineGenericMessanging } from './generic'; import { NamespaceMessagingConfig } from './types'; +import { prepareCustomEventDict } from './utils'; const REQUEST_EVENT = '@webext-core/messaging/custom-events'; const RESPONSE_EVENT = '@webext-core/messaging/custom-events/response'; @@ -89,8 +90,7 @@ export function defineCustomEventMessaging< sendMessage(message) { const reqDetail = { message, namespace, instanceId }; const requestEvent = new CustomEvent(REQUEST_EVENT, { - // @ts-expect-error not exist cloneInto types because implemented only in Firefox. - detail: typeof cloneInto !== 'undefined' ? cloneInto(reqDetail, window) : reqDetail, + detail: prepareCustomEventDict(reqDetail), }); return sendCustomMessage(requestEvent); }, @@ -105,8 +105,7 @@ export function defineCustomEventMessaging< const resDetail = { response, message, instanceId, namespace }; const responseEvent = new CustomEvent(RESPONSE_EVENT, { - // @ts-expect-error not exist cloneInto types because implemented only in Firefox. - detail: typeof cloneInto !== 'undefined' ? cloneInto(resDetail, window) : resDetail, + detail: prepareCustomEventDict(resDetail), }); window.dispatchEvent(responseEvent); }; @@ -114,6 +113,9 @@ export function defineCustomEventMessaging< window.addEventListener(REQUEST_EVENT, requestListener); return () => window.removeEventListener(REQUEST_EVENT, requestListener); }, + verifyMessageData(data) { + return structuredClone(data); + }, }); return { diff --git a/packages/messaging/src/generic.ts b/packages/messaging/src/generic.ts index d63ae8c..842677b 100644 --- a/packages/messaging/src/generic.ts +++ b/packages/messaging/src/generic.ts @@ -25,6 +25,7 @@ interface GenericMessagingConfig< message: Message & TMessageExtension, ) => void | Promise<{ res: any } | { err: unknown }>, ): RemoveListenerCallback; + verifyMessageData?(data: T): MaybePromise; } /** @@ -109,12 +110,13 @@ export function defineGenericMessanging< data: TProtocolMap[TType], ...args: TSendMessageArgs ): Promise { - const message: Message = { + const _message: Message = { id: getNextId(), type: type, data, timestamp: Date.now(), }; + const message = (await config.verifyMessageData?.(_message)) ?? _message; config.logger?.debug(`[messaging] sendMessage {id=${message.id}} ─ᐅ`, message, ...args); const response = await config.sendMessage(message, ...args); @@ -150,6 +152,9 @@ export function defineGenericMessanging< const res = listener(message); return Promise.resolve(res) + .then(res => { + return config.verifyMessageData?.(res) ?? res; + }) .then(res => { config?.logger?.debug(`[messaging] onMessage {id=${message.id}} ─ᐅ`, { res }); return { res }; diff --git a/packages/messaging/src/utils.ts b/packages/messaging/src/utils.ts new file mode 100644 index 0000000..c839016 --- /dev/null +++ b/packages/messaging/src/utils.ts @@ -0,0 +1,10 @@ +/** + * @description In firefox, when dispatching events externally from web-extension, it's necessary to clone all properties of the dictionary. ref: https://github.com/aklinker1/webext-core/pull/70#discussion_r1775031410 + */ +export function prepareCustomEventDict( + data: T, + options: { targetScope?: object } = { targetScope: window ?? undefined }, +): T { + // @ts-expect-error not exist cloneInto types because implemented only in Firefox. + return typeof cloneInto !== 'undefined' ? cloneInto(data, options.targetScope) : data; +} diff --git a/packages/messaging/src/window.ts b/packages/messaging/src/window.ts index b566175..aa1d79f 100644 --- a/packages/messaging/src/window.ts +++ b/packages/messaging/src/window.ts @@ -106,6 +106,9 @@ export function defineWindowMessaging< window.addEventListener('message', listener); return () => window.removeEventListener('message', listener); }, + verifyMessageData(data) { + return structuredClone(data); + }, }); return {