nab 0.8.2

Token-optimized HTTP client for LLMs — fetches any URL as clean markdown
Documentation
# Cookie Subdomain Matching Fix

## Problem

When fetching `areena.yle.fi`, nab reported "0 cookies for areena.yle.fi", but when fetching `yle.fi` it found "8 cookies from brave".

The issue was that cookies set on `.yle.fi` (parent domain with leading dot) were not being sent to subdomains like `areena.yle.fi`.

## Root Causes

### 1. Native Rust Cookie Extraction (SQL Query)

**Original buggy code:**
```rust
let query = format!(
    "SELECT name, value, encrypted_value FROM cookies WHERE host_key LIKE '%{domain}' OR host_key LIKE '%.{domain}'"
);
```

**Problem:** This LIKE pattern doesn't match parent domain cookies. For `areena.yle.fi`, it would look for:
- `host_key LIKE '%areena.yle.fi'` - matches `areena.yle.fi` but not `.yle.fi`
- `host_key LIKE '%.areena.yle.fi'` - matches `.areena.yle.fi` but not `.yle.fi`

**Fix:** Generate exact match conditions for the domain and all parent domains:
```rust
// For areena.yle.fi, generate:
// host_key = 'areena.yle.fi' OR host_key = '.areena.yle.fi' OR host_key = '.yle.fi' OR host_key = '.fi'
let domain_parts: Vec<&str> = domain.split('.').collect();
let mut conditions = vec![
    format!("host_key = '{domain}'"),           // Exact match
    format!("host_key = '.{domain}'"),          // Parent domain with dot
];

// Add parent domain matches
for i in 1..domain_parts.len() {
    let parent = domain_parts[i..].join(".");
    conditions.push(format!("host_key = '.{parent}'"));
}

let where_clause = conditions.join(" OR ");
```

### 2. Python Fallback (browser_cookie3)

**Original buggy code:**
```python
cj = bc.brave(domain_name='{domain}')
cookies = {c.name: c.value for c in cj if '{domain}' in c.domain}
```

**Problems:**
1. `browser_cookie3`'s `domain_name` parameter doesn't support subdomain matching - it only returns cookies for exact domain matches
2. The filter `if '{domain}' in c.domain` would fail even if cookies were returned, because `"areena.yle.fi"` is not contained in `".yle.fi"`

**Fix:** Fetch all cookies and implement proper RFC 6265 cookie domain matching:
```python
# Don't use domain_name parameter
cj = bc.brave()

def matches_cookie_domain(cookie_domain, request_domain):
    if cookie_domain.startswith('.'):
        # Parent domain with leading dot - matches request domain and all subdomains
        parent = cookie_domain[1:]  # Remove leading dot
        return request_domain == parent or request_domain.endswith('.' + parent)
    else:
        # No leading dot - exact match only
        return cookie_domain == request_domain

cookies = {c.name: c.value for c in cj if matches_cookie_domain(c.domain, '{domain}')}
```

## Cookie Domain Matching Rules (RFC 6265)

- Cookie on `.example.com` matches `example.com`, `sub.example.com`, `sub.sub.example.com`, etc.
- Cookie on `example.com` (no leading dot) matches only `example.com` exactly
- Cookie on `.sub.example.com` matches `sub.example.com` and `deeper.sub.example.com`

## Testing

Created test suite in `tests/cookie_subdomain_test.sh` that verifies:
1. Subdomain (`areena.yle.fi`) finds parent domain cookies (`.yle.fi`)
2. Parent domain (`yle.fi`) finds its own cookies (`.yle.fi`)

Run with:
```bash
./tests/cookie_subdomain_test.sh
```

## Files Changed

- `src/auth/cookies/` (originally `src/auth.rs`, restructured in v0.6.0):
  - Fixed `get_cookies_native()` SQL query generation
  - Fixed `get_cookies_via_python()` cookie filtering
  - Added debug logging for cookie queries

## Verification

Before fix:
```bash
$ nab fetch https://areena.yle.fi --cookies brave
# No cookie message (0 cookies loaded)
```

After fix:
```bash
$ nab fetch https://areena.yle.fi --cookies brave
🍪 Loaded 8 cookies from brave
```

Both subdomain and parent domain now correctly match cookies:
- `areena.yle.fi` → finds 8 cookies from `.yle.fi`
- `yle.fi` → finds 8 cookies from `.yle.fi`