Replaces the popup's regex-chain humanizeError with a total lookup over every error code returned by extension/src/service-worker/router/. A generated test discovers codes via grep so the registry can't drift. The popup keeps its small set of regex translators for Rust/serde error phrasing that doesn't go through the router's error vocabulary. Subsumes B2 — fullscreen consumer lands in the next commit.
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
export interface ErrorCta {
|
|
label: string;
|
|
action?: 'unlock' | 'reload_extension' | 'open_setup';
|
|
}
|
|
|
|
export interface ErrorCopy {
|
|
title: string;
|
|
body: string;
|
|
cta?: ErrorCta;
|
|
}
|
|
|
|
const UNLOCK_CTA: ErrorCta = { label: 'Unlock vault', action: 'unlock' };
|
|
|
|
export const ERROR_COPY: Record<string, ErrorCopy> = {
|
|
vault_locked: {
|
|
title: 'Vault locked',
|
|
body: 'Unlock your vault to continue.',
|
|
cta: UNLOCK_CTA,
|
|
},
|
|
unauthorized_sender: {
|
|
title: 'Action not allowed',
|
|
body: 'This action is not allowed from here.',
|
|
},
|
|
unknown_message_type: {
|
|
title: 'Internal error',
|
|
body: 'The extension received an unknown request — try reloading.',
|
|
cta: { label: 'Reload extension', action: 'reload_extension' },
|
|
},
|
|
origin_mismatch: {
|
|
title: 'Wrong site',
|
|
body: 'This login belongs to a different site — refusing to leak credentials cross-origin.',
|
|
},
|
|
not_a_login: {
|
|
title: 'Not a login',
|
|
body: 'That item does not have a username and password to fill.',
|
|
},
|
|
no_totp: {
|
|
title: 'No 2FA on this item',
|
|
body: 'This item does not have a TOTP secret configured.',
|
|
},
|
|
invalid_sender_url: {
|
|
title: 'Cannot read tab URL',
|
|
body: 'The current tab has no recognizable URL — try reloading the page.',
|
|
},
|
|
tab_navigated: {
|
|
title: 'Tab changed',
|
|
body: 'The browser tab changed before the action could complete — try again.',
|
|
},
|
|
captured_tab_gone: {
|
|
title: 'Tab is gone',
|
|
body: 'The browser tab closed before the action could complete — try again.',
|
|
},
|
|
item_not_found: {
|
|
title: 'Item not found',
|
|
body: 'That item is no longer in the vault — it may have been deleted from another device.',
|
|
},
|
|
attachment_not_found: {
|
|
title: 'Attachment missing',
|
|
body: 'The attachment is referenced in the item but is not present in the vault.',
|
|
},
|
|
upload_failed: {
|
|
title: 'Upload failed',
|
|
body: 'Could not upload the attachment — check your connection and try again.',
|
|
},
|
|
download_failed: {
|
|
title: 'Download failed',
|
|
body: 'Could not download the attachment — check your connection and try again.',
|
|
},
|
|
'invalid base32 secret': {
|
|
title: 'Invalid secret',
|
|
body: 'The TOTP secret must be valid Base32 (letters A-Z and digits 2-7 only).',
|
|
},
|
|
'no items to import': {
|
|
title: 'Nothing to import',
|
|
body: 'The CSV did not contain any importable items.',
|
|
},
|
|
'no reference image stored locally': {
|
|
title: 'No reference image',
|
|
body: 'This device has no reference image saved locally — re-attach the device or restore from backup.',
|
|
},
|
|
'remote already contains a Relicario vault': {
|
|
title: 'Vault already exists',
|
|
body: 'The selected repository already contains a vault — use Attach existing instead of Create new.',
|
|
},
|
|
'Extension not configured. Run setup first.': {
|
|
title: 'Extension not configured',
|
|
body: 'Run setup before using this action.',
|
|
cta: { label: 'Open setup', action: 'open_setup' },
|
|
},
|
|
'Reference image not set. Run setup first.': {
|
|
title: 'Reference image missing',
|
|
body: 'Run setup to save your reference image.',
|
|
cta: { label: 'Open setup', action: 'open_setup' },
|
|
},
|
|
};
|
|
|
|
export function lookupErrorCopy(code: string): ErrorCopy {
|
|
return ERROR_COPY[code] ?? {
|
|
title: 'Something went wrong',
|
|
body: code,
|
|
};
|
|
}
|