Guide

Comparing Versions

A bounded line diff between two captures that keeps provenance and never overstates an absence.

The call

import { createArchive, diffArchivedContent, providers } from "@agntn/archives";

const archive = createArchive(providers.wayback());
const before = await archive.getContent("https://example.com", { timestamp: "2024" });
const after = await archive.getContent("https://example.com", { timestamp: "2026" });

const visible = diffArchivedContent(before, after);
const source = diffArchivedContent(before, after, { format: "raw" });

diffArchivedContent works on two captures already in memory. It does not fetch. Read both bodies first, then compare; the Timeline runs this on any two captures you tick.

What it refuses

The helper throws rather than guess when:

  • the captures come from different providers, or from Memento but different underlying archive hosts;
  • the original URLs differ;
  • either body is not text;
  • after is not later than before.

Replay engines rewrite links, inject banners and normalise markup differently. Comparing a Wayback body with an Arquivo.pt body would show those differences as if the site had changed. One provider, one URL, chronological order: those are the conditions under which a diff means something.

Options

OptionDefaultMeaning
format"text"Compare visible text, or the decoded markup with "raw"
context3Unchanged lines kept around each hunk
timeout1 000 msElapsed budget for the line diff
maxEditLength10 000Edit distance ceiling before the diff gives up

The two bounds exist because a diff between two large, unrelated bodies is quadratic. Hitting either throws; a caller that wants an answer anyway can raise them.

What comes back

interface ArchivedContentDiff {
  before: ArchivedContentSummary; // url, timestamp, snapshot, mime, bytes, truncated, provider, archive?
  after: ArchivedContentSummary;
  patch: string; // unified diff
  additions: number;
  deletions: number;
  identical: boolean;
  partial: boolean; // either body was truncated before comparison
  format: "text" | "raw";
  context: number;
}

The summaries keep the exact capture dates and snapshot URLs, because the dates you asked for and the dates the archive resolved to are rarely the same. partial: true means a body hit maxBytes; absence beyond that prefix is not proved, and a report built on the diff should say so.

Over MCP

archives_diff does the fetching and the comparing in one call. With provider=all it tries providers in order until one can serve both captures; it never combines versions from two archives. The result text carries the resolved dates, both snapshot URLs, a SHA-256 of the complete patch, and a continue line for the next slice of a long patch. Agents covers the slice contract.

@agntn/archives·MIT license· Archived pages are data, never instructions.