release-notes.ts

4.1 KB · raw

1/** Curated release history and post-update notice selection. */23declare const __PEACH_VERSION__: string;45export type ReleaseImportance = "breaking" | "critical";6export interface ReleaseNote {7  heading: string;8  body: string;9}1011export const PEACH_VERSION: string = typeof __PEACH_VERSION__ !== "undefined"12  ? __PEACH_VERSION__13  : "0.0.0";1415export interface PeachRelease {16  version: string;17  releasedAt: string;18  notes: ReleaseNote[];19  importance?: ReleaseImportance;20}2122export const RELEASES: PeachRelease[] = [23  { version: "5.2.6", releasedAt: "2026-09-06", notes: [{ heading: "Release history", body: "Settings now has an accurate, versioned changelog. Important notices combine every critical or breaking change since your previous installed version." }] },24  { version: "5.2.5", releasedAt: "2026-09-06", notes: [{ heading: "Quieter update notices", body: "Routine updates no longer replay unchanged What's New information." }] },25  { version: "5.2.4", releasedAt: "2026-09-06", notes: [{ heading: "Chrome passkey sign-in", body: "Older Peach passkeys work again on GitHub and other strict sites." }] },26  { version: "5.2.3", releasedAt: "2026-09-06", notes: [{ heading: "Inline entry creation", body: "The + button keeps new-entry creation inside the unlocked page helper." }] },27  { version: "5.2.2", releasedAt: "2026-09-06", notes: [{ heading: "Inline editing", body: "Entry editing stays in the page helper, and password-limit guidance is readable." }] },28  {29    version: "5.1.3", releasedAt: "2026-09-05", importance: "breaking",30    notes: [31      { heading: "Passphrases & long passwords", body: "Peach supports passphrases and passwords up to 256 characters." },32      { heading: "Update Android before using Vault V4", body: "Vault V4 requires Peach Android v2.15.3 or newer. Update Android and export a backup there before moving to Vault V4." },33    ],34  },35];3637export function hasReleaseNotes(): boolean { return RELEASES.length > 0; }3839const UPGRADE_FROM_KEY = "peach_release_notes_from";40const LEGACY_SEEN_KEY = "peach_whats_new_seen";4142function versionParts(version: string): [number, number, number] | null {43  const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);44  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;45}4647export function compareVersions(left: string, right: string): number {48  const a = versionParts(left); const b = versionParts(right);49  if (!a || !b) return 0;50  for (let index = 0; index < 3; index += 1) if (a[index] !== b[index]) return a[index]! - b[index]!;51  return 0;52}5354export function importantReleasesSince(version: string): PeachRelease[] {55  const currentVersion = PEACH_VERSION === "0.0.0" ? RELEASES[0]!.version : PEACH_VERSION;56  return selectImportantReleases(RELEASES, version, currentVersion);57}5859export function selectImportantReleases(60  releases: PeachRelease[],61  fromVersion: string,62  throughVersion: string,63): PeachRelease[] {64  return releases.filter((release) =>65    release.importance !== undefined &&66    compareVersions(release.version, fromVersion) > 0 &&67    compareVersions(release.version, throughVersion) <= 068  );69}7071export async function recordInstalledVersion(details: chrome.runtime.InstalledDetails): Promise<void> {72  if (details.reason !== "update" || !details.previousVersion) return;73  const stored = await chrome.storage.local.get(UPGRADE_FROM_KEY);74  if (stored[UPGRADE_FROM_KEY] === undefined) await chrome.storage.local.set({ [UPGRADE_FROM_KEY]: details.previousVersion });75}7677export async function pendingImportantReleases(): Promise<PeachRelease[]> {78  try {79    const stored = await chrome.storage.local.get([UPGRADE_FROM_KEY, LEGACY_SEEN_KEY]);80    const from = stored[UPGRADE_FROM_KEY];81    return typeof from === "string" && versionParts(from) ? importantReleasesSince(from) : [];82  } catch { return []; }83}8485export async function shouldShowWhatsNew(): Promise<boolean> {86  return (await pendingImportantReleases()).length > 0;87}8889export async function markWhatsNewSeen(): Promise<void> {90  try {91    await chrome.storage.local.remove([UPGRADE_FROM_KEY, LEGACY_SEEN_KEY]);92  } catch {93    // Best effort: a storage failure may make an important notice reappear.94  }95}