feat(host): unify typed failure results

Represent denied, timeout, unavailable, and error host outcomes with one HostFailure result shape, update the browser adapter, and keep Workout host recovery flowing through app code before UI effects.

req: host/002

req: host/005

req: local/003
This commit is contained in:
slhx agent
2026-06-12 07:58:44 +02:00
parent cc97330bd1
commit 21100aafdf
4 changed files with 109 additions and 27 deletions
+7 -7
View File
@@ -5,19 +5,19 @@
return keys.length === 1 ? { kind: keys[0], data: value[keys[0]] || {} } : null;
}
function failure(id, message) {
return { Failed: { id: id || null, message: String(message) } };
function failure(id, capability, kind, message) {
return { Failed: { id: id || null, capability: capability || null, kind, message: String(message) } };
}
async function haptic(data) {
if (!navigator.vibrate) return failure(data.id, "haptics unsupported");
if (!navigator.vibrate) return failure(data.id, "Haptics", "Unavailable", "haptics unsupported");
const pattern = data.pattern === "Warning" || data.pattern === "Error" ? [30, 40, 30] : 20;
navigator.vibrate(pattern);
return { Acknowledged: { id: data.id } };
}
async function share(data) {
if (!navigator.share) return failure(data.id, "share unsupported");
if (!navigator.share) return failure(data.id, "Share", "Unavailable", "share unsupported");
const payload = data.payload || {};
const request = {};
if (payload.title) request.title = payload.title;
@@ -28,7 +28,7 @@
return { ShareCompleted: { id: data.id, completed: true } };
} catch (error) {
if (error && error.name === "AbortError") return { ShareCompleted: { id: data.id, completed: false } };
return failure(data.id, error && error.message ? error.message : error);
return failure(data.id, "Share", "Error", error && error.message ? error.message : error);
}
}
@@ -39,10 +39,10 @@
async function perform(call) {
const request = variant(call);
if (!request) return failure(null, "invalid host call");
if (!request) return failure(null, null, "Error", "invalid host call");
if (request.kind === "Haptic") return haptic(request.data);
if (request.kind === "Share") return share(request.data);
return failure(request.data.id || null, `unsupported host call ${request.kind}`);
return failure(request.data.id || null, null, "Unavailable", `unsupported host call ${request.kind}`);
}
window.hemxBrowserHost = Object.freeze({ name: "browser-pwa", supports, perform });