```ts
export function canonicalStackMark(mark: string): string {
  if (typeof mark !== 'string') {
    throw new Error('Input must be a string');
  }

  const parts = mark.split(/[\s-]+/);

  if (parts.length !== 3) {
    throw new Error('Invalid format');
  }

  const [floorStr, wingStr, stackStr] = parts;

  const floor = parseInt(floorStr, 10);
  if (isNaN(floor) || floor < 1 || floor > 9) {
    throw new Error('Invalid floor number');
  }

  const wing = wingStr.toUpperCase();
  if (!['N', 'S', 'E', 'W'].includes(wing)) {
    throw new Error('Invalid wing letter');
  }

  const stack = parseInt(stackStr, 10);
  if (isNaN(stack) || stack < 1 || stack > 999) {
    throw new Error('Invalid stack number');
  }

  return `${floor}${wing}${stack.toString().padStart(3, '0')}`;
}
```