fix: settle showFeedbackDialog instead of hanging on older host GUIs

In the app environment showFeedbackDialog awaited an IPC reply with no
capability check. A host GUI that predates this feature (self-hosted
Puter running the live js.puter.com SDK) has no handler for the message
and never replies, so the promise documented as 'never rejects' also
never resolved.

The GUI now advertises the IPC dialogs it can answer via a
puter.gui_features param on the app iframe URL, and the SDK resolves
false when 'feedback-dialog' isn't listed. A reply timeout could not
substitute: legitimate replies only arrive when the user closes the
dialog, so any timeout would false-negative while the user is typing.
Older SDKs ignore the extra param.
This commit is contained in:
Nariman Jelveh
2026-08-11 18:19:46 -07:00
parent 1460751b41
commit 7230580b18
2 changed files with 19 additions and 0 deletions
+7
View File
@@ -558,6 +558,13 @@ const launch_app = async (options) => {
// Add locale to URL
iframe_url.searchParams.append('puter.locale', window.locale);
// Newer IPC dialogs this GUI can answer, comma-separated. The SDK
// consults this before posting a message an older GUI has no handler
// for: such a message is never replied to, and a reply timeout can't
// stand in for the check because legitimate replies only arrive when
// the user closes the dialog.
iframe_url.searchParams.append('puter.gui_features', 'feedback-dialog');
// Add options.args to URL
iframe_url.searchParams.append('puter.args', JSON.stringify(options.args ?? {}));
+12
View File
@@ -1688,6 +1688,18 @@ class UI extends EventListener {
*/
async showFeedbackDialog () {
if ( this.env === 'app' ) {
// The host GUI advertises the IPC dialogs it can answer via
// `puter.gui_features` on the app iframe's URL (see
// launch_app.js). A GUI that predates this feature has no
// handler for the message and would never reply, hanging this
// never-rejecting promise forever — and a reply timeout can't
// stand in for the check, because a legitimate reply only
// arrives when the user closes the dialog.
const features = new URLSearchParams(globalThis.location?.search ?? '')
.get('puter.gui_features')?.split(',') ?? [];
if ( ! features.includes('feedback-dialog') ) {
return false;
}
const result = await this.#postMessageAsync('showFeedbackDialog', {});
return result?.sent === true;
}