```typescript
export function openWindows(span: string, booked: string[]): string {
  if (!isValidTimeRange(span) || !areValidAppointments(booked)) {
    throw new Error('Invalid input');
  }

  const [startTime, endTime] = span.split('-').map(parseTime);
  const appointments = booked.map(parseTime);

  const freeStretches: { start: number; end: number }[] = [];

  let lastEnd = startTime;
  for (const appointment of appointments) {
    if (appointment.end < lastEnd) continue;

    if (appointment.start > lastEnd) {
      freeStretches.push({ start: lastEnd, end: appointment.start });
    }

    lastEnd = Math.max(lastEnd, appointment.end);
  }

  const hasFreeStretch = freeStretches.length > 0;
  return hasFreeStretch
    ? freeStretches.map(({ start, end }) => formatTime(start) + '-' + formatTime(end))
      .join(', ')
    : 'none';
}

function isValidTimeRange(span: string): boolean {
  const regex = /^([0-9]{2}):([0-9]{2})-([0-9]{2}):([0-9]{2})$/;
  return regex.test(span);
}

function areValidAppointments(booked: string[]): boolean {
  for (const appointment of booked) {
    if (!isValidTimeRange(appointment)) return false;
  }
  return true;
}

function parseTime(timeStr: string): number {
  const [hours, minutes] = timeStr.split(':').map(Number);
  return hours * 60 + minutes;
}

function formatTime(time: number): string {
  const hours = Math.floor(time / 60).toString().padStart(2, '0');
  const minutes = (time % 60).toString().padStart(2, '0');
  return `${hours}:${minutes}`;
}
```