```typescript
import { maxBy } 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);
  
  const n = tripDays.length;
  const dp = Array.from({ length: n + 1 }, () => Infinity);
  const prev = Array.from({ length: n + 1 }, () => -1);

  // Initialize base case for day 0
  dp[0] = 0;

  for (let i = 1; i <= n; i++) {
    for (const pass of passes) {
      if (pass.span >= i) {
        const cost = dp[i - pass.span] + pass.cost;
        if (cost < dp[i]) {
          dp[i] = cost;
          prev[i] = [tripDays[i - 1], pass.span];
        }
      }
    }
  }

  // Reconstruct the purchases
  const purchases: number[][] = [];
  let currentSum = dp[n];
  while (currentSum > 0) {
    const purchase = prev[n];
    if (purchase !== -1) {
      purchases.unshift(purchase);
      currentSum -= purchase[1] * purchase[0];
      n = purchase[0] + purchase[1] - 1;
    } else {
      throw new Error("error reconstructing plan");
    }
  }

  return { total: dp[n], purchases };
}
```