```ts
/**
 * Calculates the length in days of the longest stretch of consecutive days
 * that starts on a kept day, ends on a kept day, and holds at most grace
 * unkept days in between.
 * @param counts - Array of daily step counts.
 * @param goal - The step count goal to be considered a kept day.
 * @param grace - The maximum number of unkept days allowed in between kept days.
 * @returns Length of the longest valid stretch in days.
 * @throws Error if the goal is not positive or grace is negative.
 */
export function graceWindow(counts: number[], goal: number, grace: number): number {
  if (goal <= 0) {
    throw new Error("Goal must be a positive number.");
  }
  if (grace < 0) {
    throw new Error("Grace must be a non-negative number.");
  }

  const isKeptDay = (count: number): boolean => count >= goal;
  let maxLength = 0;
  let currentLength = 0;
  let unkeptDays = 0;

  for (let i = 0; i < counts.length; i++) {
    if (isKeptDay(counts[i])) {
      currentLength++;
      maxLength = Math.max(maxLength, currentLength);
      unkeptDays = 0;
    } else {
      if (unkeptDays < grace) {
        currentLength++;
        unkeptDays++;
      } else {
        currentLength = 0;
        unkeptDays = 0;
      }
    }
  }

  return maxLength;
}
```