```ts
export function openWindows(span: string, booked: string[]): string {
  const parseTime = (timeStr: string): [number, number] => {
    const [hours, minutes] = timeStr.split(':').map(Number);
    if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
      throw new Error('Invalid time format');
    }
    return [hours, minutes];
  };

  const formatTime = ([hours, minutes]: [number, number]): string => {
    return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
  };

  if (!/^([01]?[0-9]|2[0-3]):[0-5][0-9]-([01]?[0-9]|2[0-3]):[0-5][0-9]$/.test(span)) {
    throw new Error('Invalid span format');
  }

  const [spanStart, spanEnd] = span.split('-').map(parseTime);
  if (spanStart > spanEnd) {
    throw new Error('Invalid span range');
  }

  const sortedBooked = booked
    .map(appointment => appointment.split('-').map(parseTime))
    .sort((a, b) => a[0][0] * 60 + a[0][1] - (b[0][0] * 60 + b[0][1]));

  let currentEnd = spanStart;
  const freeWindows: [number, number][] = [];

  for (const [start, end] of sortedBooked) {
    if (start > currentEnd) {
      freeWindows.push([currentEnd, start]);
    }
    currentEnd = Math.max(currentEnd, end);
  }

  if (currentEnd < spanEnd) {
    freeWindows.push([currentEnd, spanEnd]);
  }

  return freeWindows.length === 0 ? 'none' : freeWindows.map(formatTime).join(', ');
}
```