feat(ext): typed-item TS types mirroring relicario-core serde
This commit is contained in:
@@ -1,32 +1,202 @@
|
||||
/// Full credential entry (matches Rust Entry struct in relicario-core).
|
||||
export interface Entry {
|
||||
name: string;
|
||||
url?: string;
|
||||
/// Typed-item shared TypeScript types.
|
||||
///
|
||||
/// These mirror the Rust core's serde serialization. See
|
||||
/// crates/relicario-core/src/item.rs, item_types/, and settings.rs
|
||||
/// for the source shapes.
|
||||
|
||||
// --- IDs ---
|
||||
|
||||
export type ItemId = string; // 16-char hex
|
||||
export type FieldId = string; // 16-char hex
|
||||
export type AttachmentId = string; // 16-char hex (sha256 of plaintext, truncated)
|
||||
|
||||
// --- ItemType / ItemCore ---
|
||||
|
||||
// snake_case from serde rename_all
|
||||
export type ItemType =
|
||||
| 'login' | 'secure_note' | 'identity' | 'card' | 'key' | 'document' | 'totp';
|
||||
|
||||
// ItemCore is internally-tagged on "type":
|
||||
// Login → { type: 'login', username, password, url, totp }
|
||||
export type ItemCore =
|
||||
| ({ type: 'login' } & LoginCore)
|
||||
| ({ type: 'secure_note' } & SecureNoteCore)
|
||||
| ({ type: 'identity' } & IdentityCore)
|
||||
| ({ type: 'card' } & CardCore)
|
||||
| ({ type: 'key' } & KeyCore)
|
||||
| ({ type: 'document' } & DocumentCore)
|
||||
| ({ type: 'totp' } & TotpCore);
|
||||
|
||||
// Optional fields use `?` because Rust #[serde(skip_serializing_if = "Option::is_none")]
|
||||
// omits them from the JSON; serde_wasm_bindgen produces `undefined` on read.
|
||||
|
||||
export interface LoginCore {
|
||||
username?: string;
|
||||
password: string;
|
||||
password?: string;
|
||||
url?: string;
|
||||
totp?: TotpConfig;
|
||||
}
|
||||
|
||||
export interface SecureNoteCore { body: string; }
|
||||
|
||||
export interface IdentityCore {
|
||||
full_name?: string;
|
||||
address?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
date_of_birth?: string; // "YYYY-MM-DD"
|
||||
}
|
||||
|
||||
export interface CardCore {
|
||||
number?: string;
|
||||
holder?: string;
|
||||
expiry?: { month: number; year: number };
|
||||
cvv?: string;
|
||||
pin?: string;
|
||||
kind: CardKind;
|
||||
}
|
||||
|
||||
export type CardKind = 'credit' | 'debit' | 'gift' | 'loyalty' | 'other';
|
||||
|
||||
export interface KeyCore {
|
||||
key_material: string;
|
||||
label?: string;
|
||||
public_key?: string;
|
||||
algorithm?: string;
|
||||
}
|
||||
|
||||
export interface DocumentCore {
|
||||
filename: string;
|
||||
mime_type: string;
|
||||
primary_attachment: AttachmentId;
|
||||
}
|
||||
|
||||
export interface TotpCore {
|
||||
config: TotpConfig;
|
||||
issuer?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
// --- TOTP ---
|
||||
|
||||
export type TotpKind = 'totp' | 'steam' | { hotp: { counter: number } };
|
||||
|
||||
export interface TotpConfig {
|
||||
secret: number[]; // Vec<u8> → JSON number array
|
||||
algorithm: 'sha1' | 'sha256' | 'sha512';
|
||||
digits: number;
|
||||
period_seconds: number;
|
||||
kind: TotpKind;
|
||||
}
|
||||
|
||||
// --- Sections + custom fields ---
|
||||
|
||||
export interface Section {
|
||||
name?: string;
|
||||
fields: Field[];
|
||||
}
|
||||
|
||||
export interface Field {
|
||||
id: FieldId;
|
||||
label: string;
|
||||
kind: FieldKind;
|
||||
value: FieldValue;
|
||||
hidden_by_default: boolean;
|
||||
}
|
||||
|
||||
export type FieldKind =
|
||||
| 'text' | 'multiline' | 'password' | 'concealed' | 'url' | 'email'
|
||||
| 'phone' | 'date' | 'month_year' | 'totp' | 'reference';
|
||||
|
||||
// adjacently-tagged { tag: "kind", content: "value" }
|
||||
export type FieldValue =
|
||||
| { kind: 'text'; value: string }
|
||||
| { kind: 'multiline'; value: string }
|
||||
| { kind: 'password'; value: string }
|
||||
| { kind: 'concealed'; value: string }
|
||||
| { kind: 'url'; value: string }
|
||||
| { kind: 'email'; value: string }
|
||||
| { kind: 'phone'; value: string }
|
||||
| { kind: 'date'; value: string }
|
||||
| { kind: 'month_year'; value: { month: number; year: number } }
|
||||
| { kind: 'totp'; value: TotpConfig }
|
||||
| { kind: 'reference'; value: AttachmentId };
|
||||
|
||||
// --- Attachments + history ---
|
||||
|
||||
export interface AttachmentRef {
|
||||
id: AttachmentId;
|
||||
filename: string;
|
||||
mime_type: string;
|
||||
size: number;
|
||||
created: number;
|
||||
}
|
||||
|
||||
export interface FieldHistoryEntry {
|
||||
value: string;
|
||||
replaced_at: number;
|
||||
}
|
||||
|
||||
export interface AttachmentSummary {
|
||||
id: AttachmentId;
|
||||
filename: string;
|
||||
mime_type: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
// --- Item envelope ---
|
||||
|
||||
export interface Item {
|
||||
id: ItemId;
|
||||
title: string;
|
||||
type: ItemType; // Rust r#type → JSON key "type"
|
||||
tags: string[];
|
||||
favorite: boolean;
|
||||
group?: string;
|
||||
notes?: string;
|
||||
totp_secret?: string;
|
||||
group?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created: number;
|
||||
modified: number;
|
||||
trashed_at?: number;
|
||||
core: ItemCore;
|
||||
sections: Section[];
|
||||
attachments: AttachmentRef[];
|
||||
field_history: Record<FieldId, FieldHistoryEntry[]>;
|
||||
}
|
||||
|
||||
/// Lightweight manifest entry for listing/searching without full decrypt.
|
||||
export interface ManifestEntry {
|
||||
name: string;
|
||||
url?: string;
|
||||
username?: string;
|
||||
group?: string;
|
||||
updated_at: string;
|
||||
}
|
||||
// --- Manifest (schema_version 2) ---
|
||||
|
||||
/// Encrypted manifest containing all entry metadata.
|
||||
export interface Manifest {
|
||||
entries: Record<string, ManifestEntry>;
|
||||
version: number;
|
||||
schema_version: number; // 2
|
||||
items: Record<ItemId, ManifestEntry>;
|
||||
}
|
||||
|
||||
/// Configuration for connecting to a git host.
|
||||
export interface ManifestEntry {
|
||||
id: ItemId;
|
||||
type: ItemType;
|
||||
title: string;
|
||||
tags: string[];
|
||||
favorite: boolean;
|
||||
group?: string;
|
||||
icon_hint?: string;
|
||||
modified: number;
|
||||
trashed_at?: number;
|
||||
attachment_summaries: AttachmentSummary[];
|
||||
}
|
||||
|
||||
// --- Vault settings (only the fields α touches) ---
|
||||
// Full shape lives on the Rust side and in docs/superpowers/specs/2026-04-18-relicario-typed-items-design.md
|
||||
// We leave retention/generator/caps opaque to α so we don't accidentally mutate them.
|
||||
|
||||
export interface VaultSettings {
|
||||
trash_retention: unknown;
|
||||
field_history_retention: unknown;
|
||||
generator_defaults: unknown;
|
||||
attachment_caps: unknown;
|
||||
autofill_origin_acks: Record<string, number>;
|
||||
}
|
||||
|
||||
// --- Vault config (device-local) ---
|
||||
|
||||
export interface VaultConfig {
|
||||
hostType: 'gitea' | 'github';
|
||||
hostUrl: string;
|
||||
@@ -34,20 +204,41 @@ export interface VaultConfig {
|
||||
apiToken: string;
|
||||
}
|
||||
|
||||
/// Persisted setup state in chrome.storage.local.
|
||||
export interface SetupState {
|
||||
config: VaultConfig | null;
|
||||
imageBase64: string | null;
|
||||
isConfigured: boolean;
|
||||
}
|
||||
|
||||
/// User-configurable credential capture settings.
|
||||
export interface RelicarioSettings {
|
||||
// --- Device-local UX settings (chrome.storage.local — renamed from RelicarioSettings) ---
|
||||
|
||||
export interface DeviceSettings {
|
||||
captureEnabled: boolean;
|
||||
captureStyle: 'bar' | 'toast';
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: RelicarioSettings = {
|
||||
export const DEFAULT_DEVICE_SETTINGS: DeviceSettings = {
|
||||
captureEnabled: false,
|
||||
captureStyle: 'bar',
|
||||
};
|
||||
|
||||
// --- Generator request (matches Rust GeneratorRequest — tag="kind") ---
|
||||
|
||||
export type GeneratorRequest =
|
||||
| { kind: 'bip39'; word_count: number; separator: string; capitalization: Capitalization }
|
||||
| { kind: 'random'; length: number; classes: CharClasses; symbol_charset: SymbolCharset };
|
||||
|
||||
export type Capitalization = 'lower' | 'upper' | 'first_of_each' | 'title' | 'mixed';
|
||||
export interface CharClasses { lower: boolean; upper: boolean; digits: boolean; symbols: boolean; }
|
||||
export type SymbolCharset =
|
||||
| { kind: 'safe_only' }
|
||||
| { kind: 'extended' }
|
||||
| { kind: 'custom'; value: string };
|
||||
|
||||
// Default used by the α popup "gen" button:
|
||||
export const DEFAULT_PASSWORD_REQUEST: GeneratorRequest = {
|
||||
kind: 'random',
|
||||
length: 20,
|
||||
classes: { lower: true, upper: true, digits: true, symbols: true },
|
||||
symbol_charset: { kind: 'safe_only' },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user