Files
relicario/extension/src/shared/error-copy.ts
adlee-was-taken 648dcf386e feat(ext/shared): centralize error-message copy in ERROR_COPY map
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.
2026-05-02 16:26:01 -04:00

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,
};
}