fix: remove event listeners in cleanup to prevent leakage