# Client Foundation Library

Client-side WebAssembly foundation for Rustelo's configuration-driven web applications, built with Leptos and hydration.

## Overview

The client crate transforms your **TOML configuration** into a reactive WebAssembly client application. It provides zero-configuration hydration, client-side routing, and state management - all generated from your configuration files.

> **🎯 Configuration-Driven**: 90% TOML configuration → generated client, 10% custom extensions when needed

## Architecture Pattern (PAP)

### Primary Usage: Configuration → Generated Client (90%)

Your TOML configuration becomes a complete client application:

```toml
# site/config/routes/en.toml
[[routes]]
path = "/dashboard"
component = "Dashboard" 
title_key = "dashboard-title"
description_key = "dashboard-description"
language = "en"
enabled = true
```

**Generated WebAssembly Client:**
```rust
// Generated automatically from your TOML configuration
include!(concat!(env!("OUT_DIR"), "/generated_routes.rs"));
include!(concat!(env!("OUT_DIR"), "/generated_components.rs"));

// Your app now has:
// ✅ Hydration for /dashboard route
// ✅ Reactive component: Dashboard
// ✅ i18n with dashboard-title/dashboard-description
// ✅ Client-side navigation
// ✅ Theme system integration
```

### Secondary Usage: Extension Patterns (10%)

When configuration isn't sufficient, extend with custom client code:

```rust
// Custom client behavior for complex interactions
use client::{hydrate_with_config, ClientConfig, CustomHydrationConfig};

#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
    // Foundation handles 90% through configuration
    let config = ClientConfig::from_generated()
        // Add 10% custom behavior when needed
        .with_custom_analytics()
        .with_advanced_animations()
        .with_realtime_features();
        
    client::hydrate_with_config(config);
}
```

## Quick Start Patterns

### Pattern 1: Zero-Config Hydration (Recommended)

Most applications need only configuration, no client code:

```rust
// In your application's src/main.rs (WASM target)
use client;

#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
    // Hydrates based on your TOML route configuration
    // Components generated from site/config/routes/*.toml
    client::hydrate();
}
```

**What this provides:**
- ✅ Automatic hydration for all configured routes
- ✅ Client-side navigation between configured pages
- ✅ Reactive i18n from your fluent files
- ✅ Theme system with CSS custom properties
- ✅ Authentication state management (if auth feature enabled)

### Pattern 2: Configuration Validation

Validate your TOML configuration during client build:

```rust
use client::{validate_client_config, ClientConfigError};
use core_types::RoutesConfig;

fn main() -> Result<(), ClientConfigError> {
    // Load your route configuration from TOML
    let toml_content = include_str!("../site/config/routes/en.toml");
    let routes_config: RoutesConfig = toml::from_str(toml_content)?;
    
    // Validate configuration before building WebAssembly
    validate_client_config(&routes_config)?;
    
    println!("✅ Client configuration is valid");
    println!("📦 Ready to build WebAssembly with {} routes", 
             routes_config.routes.len());
    Ok(())
}
```

### Pattern 3: Custom Client Extensions

For the 10% case where configuration can't express your needs:

```rust
use client::{AppComponent, ClientBuilder, HydrationOptions};
use leptos::prelude::*;

#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
    // Foundation provides 90% from configuration
    let base_app = client::create_configured_app();
    
    // Add 10% custom client functionality
    let custom_app = ClientBuilder::from(base_app)
        .with_custom_component("Dashboard", || {
            view! {
                // Generated base from TOML config
                <client::GeneratedDashboard />
                // Plus custom client-side features
                <RealtimeMetrics />
                <AdvancedCharts />
            }
        })
        .with_client_side_analytics()
        .with_service_worker()
        .build();
    
    // Hydrate with both generated + custom functionality
    leptos::mount::hydrate_body(|| custom_app);
}
```

## Configuration-Driven Features

### Route-Based Hydration

Your TOML routes automatically become hydration targets:

```toml
# site/config/routes/en.toml
[[routes]]
path = "/products/{category}/{slug}"
component = "ProductDetail"
title_key = "product-title"
requires_auth = false
enabled = true

[[routes]]
path = "/admin/dashboard"
component = "AdminDashboard"
requires_auth = true
enabled = true
```

**Generated Client Behavior:**
```rust
// Automatically generated from your TOML
fn handle_route_hydration(path: &str) {
    match resolve_configured_route(path) {
        Some(RouteInfo { component: ProductDetail, requires_auth: false, .. }) => {
            hydrate_product_detail_component(path);
        }
        Some(RouteInfo { component: AdminDashboard, requires_auth: true, .. }) => {
            if user_is_authenticated() {
                hydrate_admin_dashboard_component(path);
            } else {
                redirect_to_login();
            }
        }
        None => hydrate_not_found_component(path),
    }
}
```

### Content-Type Integration

Your `content-kinds.toml` drives client-side content handling:

```toml
# content/content-kinds.toml
[blog]
title = "Blog Posts"
directory = "blog" 
features = ["categories", "tags", "comments", "search"]
client_features = ["infinite-scroll", "live-search", "social-sharing"]

[documentation]
title = "Documentation"
directory = "docs"
features = ["toc", "search", "versioning"]
client_features = ["collapsible-nav", "keyboard-shortcuts"]
```

**Generated Client Features:**
```rust
// Blog posts get client-side enhancements automatically
impl BlogPostClient {
    // Generated from content-kinds.toml client_features
    fn enable_infinite_scroll(&self) { /* ... */ }
    fn enable_live_search(&self) { /* ... */ }
    fn enable_social_sharing(&self) { /* ... */ }
}

// Documentation gets different client features
impl DocumentationClient {
    // Generated from different client_features configuration
    fn enable_collapsible_nav(&self) { /* ... */ }
    fn enable_keyboard_shortcuts(&self) { /* ... */ }
}
```

### Theme System Integration

Themes configured in TOML become CSS custom properties:

```toml
# site/config/theme.toml
[themes.light]
primary = "#3B82F6"
background = "#FFFFFF"
text = "#1F2937"

[themes.dark]
primary = "#60A5FA"
background = "#111827" 
text = "#F9FAFB"
```

**Generated Client Theme System:**
```rust
// Theme switching generated from TOML configuration
pub fn apply_theme(theme_name: &str) {
    let theme_config = get_theme_from_config(theme_name);
    
    // Updates CSS custom properties automatically
    set_css_property("--ds-primary", &theme_config.primary);
    set_css_property("--ds-bg", &theme_config.background);
    set_css_property("--ds-text", &theme_config.text);
    
    // Persists theme choice in localStorage
    store_theme_preference(theme_name);
}
```

## WebAssembly Integration

### Zero-Config WASM Build

The client crate builds to WebAssembly automatically:

```bash
# Your routes configuration drives what gets compiled to WASM
cargo leptos build

# Generated files:
# - target/site/pkg/client.wasm (your configured app)  
# - target/site/pkg/client.js (generated bindings)
# - target/site/client_bg.wasm (optimized binary)
```

### Bundle Size Optimization

Configuration drives what gets included in the WASM bundle:

```toml
# Only enabled features are compiled to WASM
[features]
default = ["hydrate"]
auth = ["oauth2", "jwt"]
analytics = ["tracking", "metrics"] 
performance = ["lazy-loading", "code-splitting"]
```

**Generated Bundle Strategy:**
- **Base bundle**: Routes + components from TOML configuration
- **Feature bundles**: Only enabled features (auth, analytics, etc.)
- **Lazy bundles**: Route-based code splitting for large applications
- **Shared chunks**: Common dependencies across generated components

## Hydration System

### SSR-to-Client Handoff

The client seamlessly takes over from server-rendered HTML:

```html
<!-- Server renders this (from your TOML config) -->
<div id="app" data-leptos-config="...">
  <header><!-- Navigation from routes configuration --></header>
  <main><!-- Page content from component configuration --></main>
  <footer><!-- Footer from layout configuration --></footer>
</div>
```

```rust
// Client hydrates this automatically
#[wasm_bindgen::prelude::wasm_bindgen] 
pub fn hydrate() {
    // Reads data-leptos-config to understand server state
    // Hydrates components based on route configuration
    // Activates client-side routing for configured routes
    client::hydrate();
}
```

### Hydration Debugging

Built-in debugging for development:

```rust
use client::hydration;

#[cfg(debug_assertions)]
fn debug_hydration() {
    // Shows which components are being hydrated
    hydration::enable_debug_logging();
    
    // Validates server-client state consistency
    hydration::validate_state_consistency(); 
    
    // Reports hydration performance metrics
    hydration::report_performance_metrics();
}
```

## Client State Management

### Configuration-Driven State

Your TOML configuration determines what state is managed:

```toml
# site/config/client-state.toml
[global_state]
theme = { type = "persisted", default = "light" }
language = { type = "reactive", default = "en" } 
auth = { type = "secure", default = "unauthenticated" }

[page_state.dashboard]
filters = { type = "local", default = {} }
sort_order = { type = "persisted", default = "date_desc" }
```

**Generated State Management:**
```rust
// State providers generated from configuration
#[component]
pub fn StateProviders(children: Children) -> impl IntoView {
    view! {
        // Generated from global_state configuration
        <ThemeProvider default="light" persisted=true>
            <LanguageProvider default="en" reactive=true>
                <AuthProvider default="unauthenticated" secure=true>
                    {children()}
                </AuthProvider>
            </LanguageProvider>
        </ThemeProvider>
    }
}
```

### Reactive i18n Integration

Language switching triggers reactive updates:

```rust
// Generated from your fluent files and route configuration  
use client::i18n::{use_i18n, switch_language};

#[component] 
pub fn LanguageSwitcher() -> impl IntoView {
    let i18n = use_i18n(); // Connected to route configuration
    
    view! {
        <select on:change=move |ev| {
            let new_lang = event_target_value(&ev);
            // Updates route, reloads content, persists choice
            switch_language(&new_lang);
        }>
            // Options generated from available fluent files
            <option value="en">English</option>
            <option value="es">Español</option>
            <option value="fr">Français</option>
        </select>
    }
}
```

## Extension Patterns

### Custom Component Integration

Extend generated components with custom behavior:

```rust
use client::extensions::{ComponentExtension, extend_component};

// Extend a generated component with custom client functionality
#[component]
pub fn ExtendedDashboard() -> impl IntoView {
    // Get the base component from TOML configuration
    let base_dashboard = client::get_generated_component("Dashboard");
    
    // Add custom client-side features
    let (realtime_data, _) = create_signal(Vec::new());
    
    // Custom WebSocket connection for real-time updates
    create_effect(move |_| {
        establish_websocket_connection("wss://api.example.com/dashboard");
    });
    
    view! {
        // Base component (90% from configuration)
        {base_dashboard}
        
        // Custom extensions (10% when needed)
        <RealtimeMetricsPanel data=realtime_data />
        <AdvancedCharting />
        <CustomNotifications />
    }
}
```

### Build-Time Extensions

Extend the build system for custom client generation:

```rust
// In your build.rs
use client::build_extensions::{ClientBuildExtension, register_extension};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Foundation generates 90% from TOML configuration
    client::generate_from_configuration()?;
    
    // Add 10% custom build-time generation
    register_extension(CustomDashboardExtension)?;
    register_extension(RealtimeComponentsExtension)?;
    
    Ok(())
}

struct CustomDashboardExtension;

impl ClientBuildExtension for CustomDashboardExtension {
    fn generate_code(&self) -> Result<String, String> {
        Ok(r#"
        // Custom generated client code
        #[component]
        pub fn CustomDashboard() -> impl IntoView {
            view! { /* custom dashboard implementation */ }
        }
        "#.to_string())
    }
}
```

## Performance Optimization

### Configuration-Based Optimization

Performance features enabled through configuration:

```toml
# site/config/performance.toml
[client_optimization]
bundle_splitting = true
lazy_loading = true
preload_critical = true
tree_shaking = true
compression = "gzip"

[wasm_optimization]
size_optimization = "aggressive"
debug_symbols = false
lto = true
panic_strategy = "abort"
```

**Generated Optimization Strategy:**
```rust
// Build configuration drives WASM optimization
[profile.release]
lto = true                    # From wasm_optimization.lto
panic = "abort"              # From wasm_optimization.panic_strategy
codegen-units = 1           # From size_optimization = "aggressive"
opt-level = "s"             # Size optimization

// Runtime optimization based on client_optimization
lazy_static! {
    static ref PRELOAD_ROUTES: Vec<&'static str> = vec![
        "/dashboard",   // From preload_critical configuration
        "/profile",     // High-traffic routes from analytics
    ];
}
```

### Route-Based Code Splitting

TOML routes automatically generate code splits:

```toml
[[routes]]
path = "/admin/*"
component = "AdminSection"  
lazy_load = true           # Generates separate WASM chunk

[[routes]] 
path = "/*"
component = "PublicSection"
lazy_load = false          # Included in main bundle
```

**Generated Code Splitting:**
```rust
// Automatically generated lazy loading
async fn load_admin_component() -> Result<AdminComponent, LoadError> {
    // Loads admin.wasm chunk only when needed
    let module = wasm_bindgen_futures::JsFuture::from(
        js_sys::eval("import('./chunks/admin.wasm')")
    ).await?;
    
    Ok(AdminComponent::from_module(module))
}
```

## Browser Integration

### Web APIs Access

Safe WebAssembly access to browser APIs:

```rust
use client::web_apis::{LocalStorage, SessionStorage, Notifications, Location};

// Safe wrappers generated for each configured feature
#[component]
pub fn ClientFeatures() -> impl IntoView {
    let storage = LocalStorage::new(); // Type-safe localStorage wrapper
    let notifications = Notifications::new(); // Permission handling
    let location = Location::new(); // URL manipulation
    
    // All browser APIs are safely wrapped for WASM usage
    view! {
        <button on:click=move |_| {
            storage.set("theme", "dark").unwrap();
            notifications.show("Theme changed").unwrap();
            location.reload().unwrap();
        }>
            "Change Theme"
        </button>
    }
}
```

### Service Worker Integration

Optional service worker for offline functionality:

```toml
# site/config/pwa.toml
[service_worker]
enabled = true
cache_routes = ["all"]  # Cache all configured routes
offline_fallbacks = true
background_sync = true
```

**Generated Service Worker:**
```javascript
// Generated from your route configuration  
const CACHE_ROUTES = [
    '/dashboard',    // From your routes TOML
    '/profile',      // All enabled routes cached
    '/settings'      // Automatically included
];

// Routes become offline-available automatically
self.addEventListener('fetch', event => {
    if (CACHE_ROUTES.includes(url.pathname)) {
        event.respondWith(
            caches.match(event.request)
                .then(response => response || fetch(event.request))
        );
    }
});
```

## Testing Integration

### Configuration-Based Testing

Test your TOML configuration directly:

```rust
#[cfg(test)]
mod client_config_tests {
    use super::*;
    use client::testing::{mock_hydration, validate_routes};
    
    #[test]
    fn test_route_configuration() {
        let routes_config = load_test_config("routes/en.toml");
        
        // Validate all routes are properly configured
        let validation = validate_routes(&routes_config);
        assert!(validation.is_ok());
        
        // Test hydration for each configured route
        for route in &routes_config.routes {
            let result = mock_hydration(&route.path);
            assert!(result.is_ok(), "Failed to hydrate route: {}", route.path);
        }
    }
    
    #[test] 
    fn test_client_state_management() {
        let state_config = load_test_config("client-state.toml");
        
        // Validate state providers work correctly
        let providers = create_state_providers(&state_config);
        assert!(providers.theme_provider.is_some());
        assert!(providers.i18n_provider.is_some());
    }
}
```

### Component Testing in WASM

Test generated components in WebAssembly environment:

```rust
use wasm_bindgen_test::*;
use client::testing::WasmTestHarness;

wasm_bindgen_test_configure!(run_in_browser);

#[wasm_bindgen_test]
async fn test_dashboard_hydration() {
    let harness = WasmTestHarness::new();
    
    // Test hydration of configured component
    let dashboard = harness.hydrate_component("Dashboard", "/dashboard").await;
    assert!(dashboard.is_ok());
    
    // Test client-side navigation
    let result = harness.navigate_to("/profile").await;
    assert!(result.is_ok());
    
    // Test reactive state updates
    harness.update_theme("dark").await;
    let theme = harness.get_current_theme().await;
    assert_eq!(theme, "dark");
}
```

## API Reference

### Core Functions
- **`client::hydrate()`** - Zero-config hydration from TOML routes
- **`client::hydrate_with_config(config)`** - Custom hydration configuration
- **`client::create_configured_app()`** - App from TOML configuration
- **`client::validate_client_config(config)`** - Validate TOML configuration

### Configuration Types
- **`ClientConfig`** - Client-side configuration builder
- **`HydrationOptions`** - Hydration behavior configuration  
- **`StateConfig`** - Client state management configuration
- **`PerformanceConfig`** - WASM optimization configuration

### Extension Points
- **`ComponentExtension`** - Extend generated components
- **`ClientBuildExtension`** - Extend build-time generation
- **`StateExtension`** - Extend state management
- **`RouteExtension`** - Extend routing behavior

## Examples

Complete usage examples are available in the `examples/` directory:

- **[Basic Hydration](examples/basic_hydration.rs)** - Zero-config TOML → WASM
- **[Custom Extensions](examples/custom_extensions.rs)** - 10% custom client code
- **[State Management](examples/state_management.rs)** - Reactive state patterns
- **[Performance Optimization](examples/performance_optimization.rs)** - WASM optimization
- **[Testing Strategies](examples/testing_strategies.rs)** - Client testing patterns

## Best Practices

1. **Start with configuration** - Use TOML files to define your client behavior
2. **Validate early** - Use `validate_client_config()` in build scripts
3. **Extend sparingly** - Only add custom code when configuration can't express needs
4. **Test configurations** - Validate TOML configs with automated tests
5. **Monitor bundle size** - Use configuration to control what's included in WASM
6. **Profile hydration** - Use built-in debugging to optimize hydration performance

## Contributing

Contributions are welcome! Please see our [Contributing Guidelines](https://github.com/yourusername/rustelo/blob/main/CONTRIBUTING.md).

## License

This project is licensed under the MIT License - see the [LICENSE](https://github.com/yourusername/rustelo/blob/main/LICENSE) file for details.
