```ts
/** The cheapest set of travel passes covering every trip day. */

import { maxBy, sortBy } from "lodash";

function validatePlan(tripDays: number[], passes: { span: number; cost: number }[]): void {
  for (const day of tripDays) {
    if (!Number.isInteger(day) || day < 1) {
      throw new Error("trip days must be positive integers");
    }
  }
  for (let i = 1; i < tripDays.length; i += 1) {
    if (tripDays[i] <= tripDays[i - 1]) {
      throw new Error("trip days must be strictly increasing");
    }
  }
  if (passes.length === 0) {
    throw new Error("at least one pass kind is required");
  }
  for (const pass of passes) {
    if (!Number.isInteger(pass.span) || pass.span < 1) {
      throw new Error("pass span must be a positive integer");
    }
    if (!Number.isInteger(pass.cost) || pass.cost < 0) {
      throw new Error("pass cost must be a non-negative integer");
    }
  }
}

export function cheapestPassPlan(
  tripDays: number[],
  passes: { span: number; cost: number }[],
): { total: number; purchases: number[][] } {
  validatePlan(tripDays, passes);

  if (tripDays.length === 0) {
    return { total: 0, purchases: [] };
  }

  // Sort passes by span in ascending order
  const sortedPasses = sortBy(passes, pass => pass.span);
  const passesSet = new Set<string>();

  // Find the cheapest combination of passes covering every trip day
  let totalCost = 0;
  let purchases: number[][] = [];
  let endDay = -1;

  for (const day of tripDays) {
    if (day <= endDay) continue; // Skip days already covered

    const earliestPass = sortedPasses.find(pass => pass.span >= day - endDay);
    if (!earliestPass) throw new Error("No pass covers the current day"); // This should not happen due to validation

    totalCost += earliestPass.cost;
    purchases.push([endDay + 1, earliestPass.span]);
    endDay = endDay + earliestPass.span - 1;

    while (true) {
      const nextEarliestPass = sortedPasses.find(pass => pass.span >= endDay - endDay);
      if (!nextEarliestPass || nextEarliestPass.span <= earliestPass.span) break;
      totalCost += nextEarliestPass.cost;
      purchases.push([endDay + 1, nextEarliestPass.span]);
      endDay = endDay + nextEarliestPass.span - 1;
    }
  }

  return { total: totalCost, purchases };
}
```