```python
import re

def split_segments(path: str) -> list:
    if not isinstance(path, str) or not path.startswith('/') or path.endswith('/'):
        raise ValueError("Invalid path")
    segments = path[1:].split('/')
    if any(segment == '' for segment in segments):
        raise ValueError("Empty segment inside the path")
    return segments

def match_route(pattern: str, path: str) -> dict | None:
    segments = split_segments(path)
    pattern_segments = split_segments(pattern)
    
    if '**' in pattern_segments and pattern_segments.count('**') > 1:
        raise ValueError("Pattern holding '**' more than once")
    
    captures = {}
    i, j = 0, 0
    while i < len(segments) and j < len(pattern_segments):
        segment = segments[i]
        pattern_segment = pattern_segments[j]
        
        if pattern_segment == ':name':
            if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', segment):
                raise ValueError("Invalid capture name")
            captures['name'] = segment
            i += 1
            j += 1
        elif pattern_segment == '*':
            if j + 1 < len(pattern_segments) and pattern_segments[j + 1] != '**':
                raise ValueError("'*' must be followed by '**'")
            i += 1
            j += 2
        elif pattern_segment == '**':
            while i < len(segments):
                captures['name'] = segments[i]
                i += 1
            j += 1
        else:
            if segment != pattern_segment:
                return None
            i += 1
            j += 1
    
    if i != len(segments) or j != len(pattern_segments):
        return None
    
    return captures

def first_route(patterns: list, path: str) -> int:
    for i, pattern in enumerate(patterns):
        if match_route(pattern, path) is not None:
            return i
    return -1
```