# Turbo Rate Limiter Developer API Documentation

This document describes the public APIs available for developers who want to extend or integrate with Turbo Rate Limiter.

## Table of Contents

- [Constants](#constants)
- [Filters](#filters)
- [Classes](#classes)
- [Usage Examples](#usage-examples)
- [Hooks Reference](#hooks-reference)

---

## Constants

All plugin constants are prefixed with `TURBORL_` to avoid conflicts.

### Plugin Information

| Constant | Value | Description |
|----------|-------|-------------|
| `TURBORL_VERSION` | `'1.0.0'` | Current plugin version |
| `TURBORL_PLUGIN_FILE` | `__FILE__` | Path to main plugin file |
| `TURBORL_PLUGIN_DIR` | Plugin directory path | Absolute path to plugin directory |
| `TURBORL_PLUGIN_URL` | Plugin URL | URL to plugin directory |
| `TURBORL_PLUGIN_BASENAME` | Plugin basename | WordPress plugin basename |

### Options

| Constant | Description |
|----------|-------------|
| `TURBORL_OPTION_NAME` | Option name storing filter configurations (`turbo_rate_limiter_filters`) |
| `TURBORL_SETTINGS_NAME` | Option name storing plugin settings (`turbo_rate_limiter_settings`) |

### Example Usage

```php
// Get plugin version
echo TURBORL_VERSION;

// Get plugin directory path
echo TURBORL_PLUGIN_DIR;

// Get plugin URL
echo TURBORL_PLUGIN_URL;
```

---

## Filters

### turbo_rate_limiter_trusted_proxies

Allows developers to specify trusted proxy IP addresses when the site is behind a reverse proxy (e.g., Cloudflare, AWS CloudFront, CDN). Supports both IPv4 and IPv6 addresses with CIDR notation.

#### IPv4 vs IPv6 Support

The plugin fully supports both IPv4 and IPv6 addresses:

- **IPv4 examples:** `203.0.113.50` or `203.0.113.0/24`
- **IPv6 examples:** `2400:cb00::/32` or `2606:4700::/32`

Both individual IPs and CIDR ranges are supported for both protocols.

#### Parameters

```php
apply_filters('turbo_rate_limiter_trusted_proxies', array $proxies )
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `$proxies` | `array` | Array of trusted proxy IPs or CIDR ranges (IPv4: '203.0.113.0/24', IPv6: '2400:cb00::/32') |

#### Default Value

```php
[] // Empty array by default
```

#### Supported Formats

You can specify IPs in two formats:

**1. Individual IP Addresses:**
```php
add_filter('turbo_rate_limiter_trusted_proxies', function() {
    return ['203.0.113.50', '198.51.100.100'];
});
```

**2. CIDR Ranges (Recommended for Cloudflare):**
```php
add_filter('turbo_rate_limiter_trusted_proxies', function() {
    return [
        // IPv4 ranges
        '173.245.48.0/20',
        '103.21.244.0/22',
        '103.22.200.0/22',
        '103.31.4.0/22',
        '141.101.64.0/18',
        '108.162.192.0/18',
        '190.93.240.0/20',
        '188.114.96.0/20',
        '197.234.240.0/22',
        '198.41.128.0/17',
        '162.158.0.0/15',
        '104.16.0.0/13',
        '104.24.0.0/14',
        '172.64.0.0/13',
        '131.0.72.0/22',
        // IPv6 ranges
        '2400:cb00::/32',
        '2606:4700::/32',
        '2803:f800::/32',
        '2405:b500::/32',
        '2405:8100::/32',
        '2a06:98c0::/29',
        '2c0f:f248::/32',
    ];
});
```

**📚 Reference:** [Cloudflare IP Ranges](https://www.cloudflare.com/ips/)

#### ⚠️ Important: What trusted_proxies Does NOT Do

This filter **does NOT bypass rate limiting**. It only helps the plugin correctly identify the visitor's real IP address when your site is behind a proxy.

**What happens without trusted proxies:**
- All visitors appear to come from the proxy's IP
- Everyone shares the same rate limit (incorrect behavior)

**What happens with trusted proxies configured:**
- The plugin reads the visitor's real IP from `X-Forwarded-For` header
- Each visitor gets their own rate limit (correct behavior)

#### Common Proxy IP Ranges

**Cloudflare IPv4:**
```
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22
```

**Cloudflare IPv6:**
```
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32
```

**📚 Reference:** [Cloudflare IP Ranges](https://www.cloudflare.com/ips/)

**Note:** For production use, always check the official documentation of your proxy provider for the latest IP ranges.

---

## Classes

Turbo Rate Limiter uses singleton pattern for its main classes. Use `get_instance()` to access instances.

### TURBORL_Rate_Limiter

The main rate limiter class.

```php
TURBORL_Rate_Limiter::get_instance()
```

#### Methods

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `get_instance()` | None | `TURBORL_Rate_Limiter` | Get singleton instance |
| `is_enabled()` | None | `bool` | Check if rate limiter is enabled |
| `is_test_mode()` | None | `bool` | Check if test mode is active |
| `is_debug_mode()` | None | `bool` | Check if debug mode is active |
| `clear_cache()` | None | `void` | Clear compiled filters cache |
| `set_enabled($enabled)` | `bool` | `void` | Enable/disable rate limiter |
| `set_test_mode($test_mode)` | `bool` | `void` | Enable/disable test mode |
| `set_debug_mode($debug_mode)` | `bool` | `void` | Enable/disable debug mode |
| `test_rate_limit($uri, $ip)` | `string`, `string\|null` | `array` | Test rate limit for a URI |

#### Example

```php
// Check if rate limiter is enabled
$rate_limiter = TURBORL_Rate_Limiter::get_instance();

if ($rate_limiter->is_enabled()) {
    echo 'Rate limiting is active';
}

// Test rate limit for a specific URI
$result = $rate_limiter->test_rate_limit('/api/endpoint', '192.168.1.1');

if ($result['exceeded']) {
    echo 'Limit would be exceeded!';
}
```

---

### TURBORL_Filter_Manager

Manages rate limit filter configurations.

```php
TURBORL_Filter_Manager::get_instance()
```

#### Methods

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `get_instance()` | None | `TURBORL_Filter_Manager` | Get singleton instance |
| `get_filters($enabled_only)` | `bool` (optional) | `array` | Get all filters or enabled only |
| `get_filter($id)` | `string` | `array\|null` | Get a specific filter by ID |
| `add_filter($data)` | `array` | `array\|WP_Error` | Add a new filter |
| `update_filter($id, $data)` | `string`, `array` | `array\|WP_Error` | Update an existing filter |
| `delete_filter($id)` | `string` | `bool` | Delete a filter |
| `toggle_filter($id, $enabled)` | `string`, `bool` | `array\|WP_Error` | Enable/disable a filter |
| `get_filter_count()` | None | `int` | Get total filter count |
| `get_enabled_filter_count()` | None | `int` | Get enabled filter count |
| `get_filters_grouped_by_match_type()` | None | `array` | Get filters organized by match type |

#### Filter Data Structure

```php
$filter = [
    'id'          => 'unique_id',
    'name'        => 'Filter Name',
    'uri_pattern' => '/api/',
    'match_type'  => 'starts_with', // exact, contains, starts_with, ends_with, regex
    'limit'       => 100,
    'window_value'=> 60,
    'window_unit' => 'seconds', // seconds, minutes, hours
    'action'      => '429', // 429, redirect_url, redirect_page
    'redirect_url'=> '',
    'redirect_page'=> 0,
    'enabled'     => true,
    'created_at'  => '2024-01-01 00:00:00',
    'updated_at'  => '2024-01-01 00:00:00',
];
```

#### Example

```php
$manager = TURBORL_Filter_Manager::get_instance();

// Get all filters
$filters = $manager->get_filters();

// Add a new filter
$new_filter = $manager->add_filter([
    'name'        => 'API Rate Limit',
    'uri_pattern' => '/api/',
    'match_type'  => 'starts_with',
    'limit'       => 100,
    'window_value'=> 60,
    'window_unit' => 'seconds',
    'rate_action' => '429',
    'enabled'     => true,
]);

// Disable a filter
$manager->toggle_filter('filter_id', false);
```

---

### TURBORL_Rate_Limit_Storage

Handles storage and retrieval of rate limit data.

```php
TURBORL_Rate_Limit_Storage::get_instance()
```

#### Methods

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `get_instance()` | None | `TURBORL_Rate_Limit_Storage` | Get singleton instance |
| `check_rate_limit($filter_id, $ip, $limit, $window)` | `string`, `string`, `int`, `int` | `array` | Check and increment rate limit |
| `get_count($key)` | `string` | `int` | Get current count for a key |
| `set_count($key, $count, $window)` | `string`, `int`, `int` | `bool` | Set count for a key |
| `reset_count($key)` | `string` | `bool` | Reset count for a key |
| `get_remaining($filter_id, $ip, $limit, $window)` | `string`, `string`, `int`, `int` | `int` | Get remaining requests |
| `get_client_ip()` | None | `string` | Get client IP address |
| `get_transient_key($filter_id, $ip)` | `string`, `string` | `string` | Generate storage key |

#### Example

```php
$storage = TURBORL_Rate_Limit_Storage::get_instance();

// Check rate limit
$result = $storage->check_rate_limit('filter_123', '192.168.1.1', 100, 60);

echo $result['count'];      // Current count
echo $result['limit'];      // Rate limit
echo $result['exceeded'];  // Whether limit is exceeded

// Get client IP
$ip = $storage->get_client_ip();

// Get remaining requests
$remaining = $storage->get_remaining('filter_123', '192.168.1.1', 100, 60);
echo $remaining; // e.g., 95
```

---

### TURBORL_URI_Matcher

Handles URI matching with various strategies.

```php
new TURBORL_URI_Matcher()
```

#### Methods

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `is_match($uri, $pattern, $match_type)` | `string`, `string`, `string` | `bool` | Check if URI matches pattern |
| `match_exact($uri, $pattern)` | `string`, `string` | `bool` | Exact string match |
| `match_contains($uri, $pattern)` | `string`, `string` | `bool` | Substring match |
| `match_starts_with($uri, $pattern)` | `string`, `string` | `bool` | Prefix match |
| `match_ends_with($uri, $pattern)` | `string`, `string` | `bool` | Suffix match |
| `match_regex($uri, $pattern)` | `string`, `string` | `bool` | Regular expression match |
| `validate_regex($pattern)` | `string` | `bool\|WP_Error` | Validate regex pattern |
| `get_match_types()` | None | `array` | Get available match types |

#### Example

```php
$matcher = new TURBORL_URI_Matcher();

// Check exact match
$matcher->is_match('/api/users', '/api/users', 'exact'); // true

// Check starts with
$matcher->is_match('/api/users', '/api/', 'starts_with'); // true

// Check contains
$matcher->is_match('/api/users', 'users', 'contains'); // true

// Check regex
$matcher->is_match('/api/users/123', '/api\/users\/\d+', 'regex'); // true

// Validate regex pattern
$result = $matcher->validate_regex('/api/\w+');
if (is_wp_error($result)) {
    echo $result->get_error_message();
}
```

---

## Usage Examples

### Complete Integration Example

```php
<?php
/**
 * Example: Programatically add a rate limit filter
 */

function my_add_rate_limit_filter() {
    $filter_manager = TURBORL_Filter_Manager::get_instance();
    
    $result = $filter_manager->add_filter([
        'name'        => 'Custom API Rate Limit',
        'uri_pattern' => '/my-api/',
        'match_type'  => 'starts_with',
        'limit'       => 50,
        'window_value'=> 60,
        'window_unit' => 'seconds',
        'rate_action' => '429',
        'enabled'     => true,
    ]);
    
    if (is_wp_error($result)) {
        error_log('Failed to add rate limit: ' . $result->get_error_message());
        return false;
    }
    
    return true;
}
add_action('init', 'my_add_rate_limit_filter');
```

### Check Before Making API Request

```php
<?php
/**
 * Example: Check rate limit before making external request
 */

function my_check_api_rate_limit($endpoint) {
    $rate_limiter = TURBORL_Rate_Limiter::get_instance();
    $storage = TURBORL_Rate_Limit_Storage::get_instance();
    
    $ip = $storage->get_client_ip();
    $result = $rate_limiter->test_rate_limit($endpoint, $ip);
    
    if ($result['exceeded']) {
        wp_send_json_error([
            'message' => 'Rate limit exceeded. Try again later.',
            'remaining' => 0,
        ], 429);
    }
    
    return $result;
}
```

### Configure Trusted Proxies for Real Client IP Detection

```php
<?php
/**
 * Example: Trust reverse proxies so the plugin can detect
 * the real visitor IP from X-Forwarded-For.
 */

add_filter('turbo_rate_limiter_trusted_proxies', function($proxies) {
    $proxies[] = '10.0.0.5';  // Your reverse proxy or load balancer
    $proxies[] = '10.0.0.10'; // Another trusted proxy
    return $proxies;
});

// Important: This does not bypass rate limiting.
// It only tells the plugin which proxy IPs are trusted,
// so it can resolve the real client IP correctly.
```

---

## Hooks Reference

### WordPress Hooks Used by Plugin

| Hook | Type | File | Description |
|------|------|------|-------------|
| `plugins_loaded` | Action | main | Initialize plugin |
| `init` | Action | class-rate-limiter.php | Check requests |
| `admin_menu` | Action | class-admin-page.php | Add admin menu |
| `admin_init` | Action | class-admin-page.php | Register settings |
| `admin_enqueue_scripts` | Action | class-admin-page.php | Enqueue admin assets |
| `wp_footer` | Action | class-rate-limiter.php | Output debug panel |
| `wp_ajax_*` | Action | class-admin-page.php | AJAX handlers |
| `admin_post_*` | Action | class-admin-page.php | Form handlers |

---

## Best Practices

1. **Always check if rate limiter is enabled** before making decisions
2. **Use the filter** to add trusted proxies for accurate IP detection
3. **Cache filter data** using `TURBORL_Filter_Manager::get_filters()` instead of querying repeatedly
4. **Validate regex patterns** using `TURBORL_URI_Matcher::validate_regex()` before saving
5. **Handle WP_Error objects** when adding/updating filters

---

## Support

For questions or issues, please open a support thread or contact:

- **Email:** ah.riad@gmail.com
- **WordPress.org:** Plugin support page

---

## Changelog API

```php
// Get plugin version
echo TURBORL_VERSION;

// Get filter count
$manager = TURBORL_Filter_Manager::get_instance();
echo $manager->get_filter_count();
echo $manager->get_enabled_filter_count();
```
