codex-types.ts

6.0 KB · raw

1/**2 * codex-types.ts — shared shapes for the Peach Codex.3 *4 * The Codex is a printed A4 PDF that encodes the user's encrypted vault as5 * Aztec barcodes plus optional recovery words. See /Users/june/Downloads/peach_codex_v2.md6 * for the full design doc.7 *8 * These types are the contract between four execution boundaries:9 *  - service worker (`src/background/codex-handlers.ts`)10 *  - popup library (`src/popup/codex/*`)11 *  - popup views (`src/popup/views/CodexGenerateView.tsx`, `CodexRestoreView.tsx`)12 *  - tests (`src/popup/codex/*.test.ts`)13 *14 * Bump `version` (and `ChunkEnvelope.v`) only on breaking changes to the15 * on-paper format. A v2 Codex must always be decodable by future Peach16 * versions.17 */1819import type { VaultEntry } from "./types";2021/** Payload that the Codex encodes. Compressed, chunked, erasure-coded, then printed. */22export interface CodexPayload {23  /** Format version. Increment on breaking changes. */24  version: 2;25  /** 12-char alphanumeric: `PX-XXXX-XXXX`. Identifies a vault across Codex prints. */26  verifyCode: string;27  /** Base64url-encoded JSON `{ a: slotA, b: slotB|null }` — both encrypted vault slots. */28  vaultBlob: string;29  /** Vault last-modified unix timestamp (ms). Used to compare against on-device vault on restore. */30  timestamp: number;31  /** Visible entry count for user confirmation at restore time. */32  entryCount: number;33  /** First 16 chars of SHA-256(vaultBlob), uppercase hex. Verifies reconstruction integrity. */34  vaultFingerprint: string;35  /** When this Codex PDF was generated. Printed in the footer. */36  generatedAt: number;37  /** True if the last page includes the 12 recovery words. */38  includesRecoveryWords: boolean;39}4041/**42 * One Aztec barcode's contents. Each envelope is a JSON-encoded chunk of the43 * compressed payload plus a per-chunk integrity hash.44 *45 * Field names are intentionally single letters to keep the encoded JSON46 * compact — every byte saved shrinks the printed page count.47 */48export interface ChunkEnvelope {49  /** Envelope format version. Increment on breaking changes. */50  v: 2;51  /** First 12 chars of `verifyCode` ("PX-XXXX-XXXX"). Lets the scanner reject foreign Codexes. */52  c: string;53  /** Chunk index, 0-based. */54  i: number;55  /** Total chunk count (data + parity). */56  t: number;57  /** True if this is a Reed-Solomon parity shard. */58  p: boolean;59  /** Chunk data, base64url-encoded. */60  d: string;61  /** First 8 chars of SHA-256(rawChunkBytes), uppercase hex. Catches per-chunk corruption. */62  h: string;63}6465/** Bookkeeping returned alongside the generated PDF. */66export interface CodexManifest {67  verifyCode: string;68  totalChunks: number;69  dataChunks: number;70  parityChunks: number;71  pageCount: number;72  entryCount: number;73  vaultFingerprint: string;74  generatedAt: number;75  includesRecoveryWords: boolean;76}7778/** Dependencies the generator needs from the service worker. */79export interface CodexDeps {80  getSlotA: () => Promise<string | null>;81  getSlotB: () => Promise<string | null>;82  getLastModified: () => Promise<string | null>;83  getAllEntries: () => Promise<VaultEntry[]>;84  getRecoveryWords: () => Promise<string[] | null>;85  getVerifyCode: () => Promise<string>;86  isVaultUnlocked: () => boolean;87}8889export interface CodexOptions {90  includeRecoveryWords: boolean;91}9293/** Payload sent from the popup to the SW to perform the actual vault restoration. */94export interface CodexRestorePayload {95  vaultBlob: string;96  timestamp: number;97  verifyCode: string;98  vaultFingerprint: string;99  entryCount: number;100  masterPassphrase: string;101}102103/** Vault data the SW exposes to the popup so it can build a CodexPayload. */104export interface CodexVaultSnapshot {105  slotA: string | null;106  slotB: string | null;107  lastModified: string | null;108  entryCount: number;109  recoveryWords: string[] | null;110  verifyCode: string;111  vaultUnlocked: boolean;112}113114/**115 * Every Codex error is loud and named. The `code` field is a stable identifier116 * for log analysis; the human-readable message lives in `.message`.117 */118export class CodexError extends Error {119  constructor(120    public code: CodexErrorCode,121    message: string,122  ) {123    super(message);124    this.name = "CodexError";125  }126}127128export type CodexErrorCode =129  | "VAULT_LOCKED"130  | "VAULT_EMPTY"131  | "RECOVERY_WORDS_MISSING"132  | "RECOVERY_WORDS_INVALID"133  | "COMPRESSION_ROUNDTRIP_FAILED"134  | "ERASURE_CODING_VERIFICATION_FAILED"135  | "ERASURE_CODING_CONTENT_MISMATCH"136  | "AZTEC_GENERATION_FAILED"137  | "AZTEC_ROUNDTRIP_FAILED"138  | "AZTEC_CONTENT_MISMATCH"139  | "INSUFFICIENT_CHUNKS"140  | "RECONSTRUCTION_SIMULATION_FAILED"141  | "RECONSTRUCTION_VERIFY_CODE_MISMATCH"142  | "RECONSTRUCTION_FINGERPRINT_MISMATCH"143  | "RECONSTRUCTION_COUNT_MISMATCH"144  | "PDF_GENERATION_FAILED"145  | "RS_LIBRARY_FAILED"146  | "PRO_REQUIRED"147  | "WRONG_PASSPHRASE"148  | "INVALID_VAULT_BLOB"149  | "RESTORE_FAILED";150151// ── Constants — shared across generation and restoration ─────────────────────152153/**154 * Bytes of binary data per chunk. Each chunk becomes one Aztec code; this size155 * keeps the printed code at ~28mm (CODE_SIZE in PDF rendering) while staying156 * within Aztec's 1914-byte ECC-25% capacity for compact codes.157 *158 * Conservative: leaves headroom for the JSON envelope overhead (~120 bytes).159 */160export const CHUNK_SIZE = 1024;161162/**163 * Number of parity shards. With 2 parity shards, the Codex survives the loss164 * of any 2 chunks (torn corner, coffee stain over one code, etc.) without165 * data loss. Raising this beyond 2 grows the page count meaningfully.166 */167export const PARITY_SHARDS = 2;168169/** Aztec error-correction percentage. 25% balances barcode density vs. resilience. */170export const AZTEC_ECC_PERCENT = 25;171172/** PDF layout: 6 columns × 4 rows = 24 codes per A4 page. */173export const CODES_PER_ROW = 6;174export const CODES_PER_COL = 4;175export const CODES_PER_PAGE = CODES_PER_ROW * CODES_PER_COL;176177/** Stable storage keys for Codex bookkeeping. */178export const STORAGE_KEY_VERIFY_CODE = "peach_codex_verify_code";179export const STORAGE_KEY_LAST_GENERATED = "peach_codex_last_generated";180export const STORAGE_KEY_LAST_RESTORED = "peach_last_restored_at";