From 13bb0a03081959f24212f381a2737186d91437a4 Mon Sep 17 00:00:00 2001 From: Cordero Core <127983572+cdcore09@users.noreply.github.com> Date: Sat, 29 Aug 2026 10:31:37 -0700 Subject: [PATCH] fix(webapp): resolve three errors in the webapp typecheck (#356) `npx tsc -p webapp/tsconfig.json --noEmit`, one of the checks recommended in CONTRIBUTING.md, currently fails on main with three errors. All three are declaration defects with correct runtime behavior; none changes observable behavior. - api/backup.ts: downloadAdminBackupAttachmentBlob declared a bare Uint8Array return. Since TypeScript made typed arrays generic, that widens to Uint8Array and no longer satisfies fflate's Uint8Array. The body already returns an ArrayBuffer-backed value, so this only annotates what it produces. - backup-center.ts: invalidateRemoteBrowserCacheForDestination declared a full PersistedRemoteBrowserState but builds four of its five fields. The sole caller reads .cache only, so the return type is narrowed to match what the function actually returns. - password-security-cache.ts: getPasswordSecurityState declared the public PasswordSecurityState, but startPasswordSecurityScan needs `controller`, which lives on InternalPasswordSecurityState. An internal accessor keeps `controller` off the exported type rather than widening the public API. No change to backup payload shape, archive/import whitelists, or any persisted format. Verified with tsc 5.9.3, 6.0.3, and 7.0.2 (all exit 0 for both webapp/tsconfig.json and tsconfig.json), plus npm run build and npm run i18n:validate. --- webapp/src/lib/api/backup.ts | 2 +- webapp/src/lib/backup-center.ts | 2 +- webapp/src/lib/password-security-cache.ts | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/webapp/src/lib/api/backup.ts b/webapp/src/lib/api/backup.ts index b76cb5a..4bb6ea1 100644 --- a/webapp/src/lib/api/backup.ts +++ b/webapp/src/lib/api/backup.ts @@ -197,7 +197,7 @@ export async function downloadAdminBackupAttachmentBlob( authedFetch: AuthedFetch, blobName: string, masterPasswordHash: string -): Promise { +): Promise> { const resp = await authedFetch('/api/admin/backup/blob', { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/webapp/src/lib/backup-center.ts b/webapp/src/lib/backup-center.ts index e2cb815..87255fd 100644 --- a/webapp/src/lib/backup-center.ts +++ b/webapp/src/lib/backup-center.ts @@ -186,7 +186,7 @@ export function invalidateRemoteBrowserCacheForDestination( cache: Record, pathByDestination: Record, pageByKey: Record -): PersistedRemoteBrowserState { +): Omit { return { cache: Object.fromEntries(Object.entries(cache).filter(([key]) => !key.startsWith(`${destinationId}:`))), pathByDestination: Object.fromEntries(Object.entries(pathByDestination).filter(([key]) => key !== destinationId)), diff --git a/webapp/src/lib/password-security-cache.ts b/webapp/src/lib/password-security-cache.ts index 7c74c31..0e6d310 100644 --- a/webapp/src/lib/password-security-cache.ts +++ b/webapp/src/lib/password-security-cache.ts @@ -23,7 +23,7 @@ function createState(fingerprint: string): InternalPasswordSecurityState { return { fingerprint, report: null, scannedAt: null, scanning: false, progress: { checked: 0, total: 0 }, scanError: false, controller: null }; } -export function getPasswordSecurityState(fingerprint: string): PasswordSecurityState { +function ensurePasswordSecurityState(fingerprint: string): InternalPasswordSecurityState { if (state?.fingerprint !== fingerprint) { state?.controller?.abort(); state = createState(fingerprint); @@ -31,6 +31,10 @@ export function getPasswordSecurityState(fingerprint: string): PasswordSecurityS return state; } +export function getPasswordSecurityState(fingerprint: string): PasswordSecurityState { + return ensurePasswordSecurityState(fingerprint); +} + export function readPasswordSecurityState(fingerprint: string): PasswordSecurityState | null { return state?.fingerprint === fingerprint ? state : null; } @@ -41,7 +45,7 @@ export function subscribePasswordSecurityState(listener: () => void): () => void } export function startPasswordSecurityScan(fingerprint: string, ciphers: Cipher[]): void { - const current = getPasswordSecurityState(fingerprint); + const current = ensurePasswordSecurityState(fingerprint); current.controller?.abort(); const controller = new AbortController(); const total = ciphers.filter((cipher) => Number(cipher.type) === 1 && !cipher.deletedDate && !(cipher as { deletedAt?: string | null }).deletedAt && !!cipher.login?.decPassword).length;