fix: default permissions to true on API failure to prevent UI hiding

- When the permission check API call fails (timeout, network error, etc.),
  permissions now default to true instead of false
- This prevents UI elements like the WiFi tab from disappearing when the
  permission check has a transient failure
- The API still enforces access server-side, so no security impact
- Added __checkFailed flag to PermissionMap for observability
This commit is contained in:
2026-02-27 18:12:14 -06:00
parent 0e634c84ff
commit 27755d4a00
3 changed files with 30 additions and 16 deletions
+4 -2
View File
@@ -51,12 +51,14 @@ describe("permissions helpers", () => {
});
});
it("defaults requested permissions to false on API error", async () => {
it("defaults requested permissions to true on API error and marks __checkFailed", async () => {
mockCheckPermissions.mockRejectedValueOnce(new Error("request failed"));
const result = await checkPermissions("token", ["a", "b"]);
expect(result).toEqual({ a: false, b: false });
expect(result.a).toBe(true);
expect(result.b).toBe(true);
expect(result.__checkFailed).toBe(true);
});
it("hasPermission returns true only for explicit true values", () => {
+13 -6
View File
@@ -1,6 +1,9 @@
import { optima } from "$lib";
export type PermissionMap = Record<string, boolean>;
export type PermissionMap = Record<string, boolean> & {
/** Set to `true` when the permission check itself failed (API error, timeout, etc.) */
__checkFailed?: boolean;
};
/**
* Check multiple permissions for the current user and return a map of
@@ -34,11 +37,15 @@ export async function checkPermissions(
}, {});
} catch (err) {
console.error("Permission check failed:", err);
// Default every requested permission to false on failure
return permissions.reduce<PermissionMap>((map, p) => {
map[p] = false;
return map;
}, {});
// Default every requested permission to true on failure so the UI
// doesn't hide features that the user may actually be allowed to use.
// The API will still enforce access if the user truly lacks permission.
const map = permissions.reduce<PermissionMap>((m, p) => {
m[p] = true;
return m;
}, {} as PermissionMap);
map.__checkFailed = true;
return map;
}
}