Hi Forge Team,
Our team is developing a feature where a Custom UI panel on a Jira issue opens a modal for user input. We’re using the @forge/bridge/events
API for the modal to communicate with the parent panel, but we’ve run into a very puzzling issue with unsubscribing from listeners that we’re hoping you can clarify.
We’ve found ourselves in a difficult spot where we seem to face a dilemma with two outcomes, neither of which allows for a robust, memory-safe implementation.
-
If we call
events.emit
immediately afterevents.on
, the communication fails. The parent panel never receives the event. Curiously, thePromise
fromevents.on
resolves immediately in this case, but it’s not helpful as no response is ever sent back. -
To get the communication working, we have to wrap
events.emit
in asetTimeout
. This works perfectly! The parent gets the message and sends a response back to the modal’s listener. However, when we do this, thePromise
fromevents.on
never resolves, which leaves us with no way to call.unsubscribe()
and creates a memory leak.
This brings us to our core question. We feel like we’re caught in a Catch-22. The documented method for unsubscribing seems to be unreachable in the very scenario where communication actually works.
Given this behavior, could you please provide a working example of how subscription.unsubscribe()
can be successfully invoked in this specific, asynchronous panel-to-modal scenario?
Here is a simplified code snippet from our modal that demonstrates the issue:
import { events } from "@forge/bridge";
function requestDataFromParent() {
return new Promise((resolve) => {
const listener = (payload) => {
console.log("Response received!");
// This listener works, but we have no way to unsubscribe it.
resolve(payload);
};
// We register the listener...
events.on('RESPONSE_EVENT', listener)
.then(subscription => {
// ...but this block ONLY runs if we DON'T use setTimeout,
// in which case the communication itself fails.
console.log("This block is unreachable in a working scenario.");
subscription.unsubscribe();
});
// We MUST use setTimeout for the parent to receive the event.
setTimeout(() => {
events.emit('REQUEST_EVENT', { /* ... */ });
}, 0);
});
}
We’d appreciate any insight or examples you can provide. Thanks for your help!