🐛 Fix DataCloneError in plugin postMessage communication

Fixes a crash where plugins sending messages via 'penpot.ui.sendMessage()'
could fail if their message payload contained non-serializable values like
functions or closures.

The fix adds validation using 'structuredClone()' to catch these messages
early with a helpful error message, and adds a defensive try/catch in the
modal's message handler as a safety net.

Fixes the error: 'Failed to execute postMessage on Window: ... could not
be cloned.'

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
Andrey Antukh
2026-03-12 13:43:21 +00:00
committed by Alonso Torres
parent be9b1158ed
commit 25df9f2f83
2 changed files with 22 additions and 2 deletions

View File

@@ -68,8 +68,21 @@ export function createApi(
},
sendMessage(message: unknown) {
let cloneableMessage: unknown;
try {
cloneableMessage = structuredClone(message);
} catch (err) {
console.error(
'plugin sendMessage: the message could not be cloned. ' +
'Ensure the message does not contain functions, DOM nodes, or other non-serializable values.',
err,
);
return;
}
const event = new CustomEvent('message', {
detail: message,
detail: cloneableMessage,
});
plugin.getModal()?.dispatchEvent(event);

View File

@@ -129,7 +129,14 @@ export class PluginModalElement extends HTMLElement {
return;
}
iframe.contentWindow.postMessage((e as CustomEvent).detail, '*');
try {
iframe.contentWindow.postMessage((e as CustomEvent).detail, '*');
} catch (err) {
console.error(
'plugin modal: failed to send message to iframe via postMessage.',
err,
);
}
});
this.shadowRoot.appendChild(this.wrapper);