1use async_trait::async_trait;
77
78#[cfg(feature = "cache")]
79mod cache;
80mod error;
81mod extractor;
82mod fetcher;
83#[cfg(feature = "github")]
84mod github_types;
85#[cfg(feature = "logging")]
86mod logging;
87mod preview_generator;
88mod preview_service;
89mod security;
90mod utils;
91
92#[cfg(feature = "browser")]
93mod mcp_client;
94#[cfg(feature = "browser")]
95mod browser_fetcher;
96
97#[cfg(feature = "llm")]
98mod llm_extractor;
99#[cfg(feature = "llm")]
100mod llm_providers;
101#[cfg(feature = "llm")]
102mod llm_config;
103
104#[cfg(feature = "cache")]
105pub use cache::Cache;
106pub use error::PreviewError;
107pub use extractor::MetadataExtractor;
108pub use fetcher::{FetchResult, Fetcher, FetcherConfig};
109#[cfg(feature = "github")]
110pub use github_types::{is_github_url, GitHubBasicPreview, GitHubDetailedInfo, GitHubRepository};
111#[cfg(feature = "logging")]
112pub use logging::{log_error_card, log_preview_card, setup_logging, LogConfig, LogLevelGuard};
113pub use preview_generator::{CacheStrategy, UrlPreviewGenerator};
114pub use preview_service::{PreviewService, PreviewServiceConfig, MAX_CONCURRENT_REQUESTS};
115pub use security::{ContentLimits, UrlValidationConfig, UrlValidator};
116
117#[cfg(feature = "browser")]
118pub use mcp_client::{McpClient, McpConfig, McpTransport, BrowserUsagePolicy};
119#[cfg(feature = "browser")]
120pub use browser_fetcher::{BrowserFetcher, BrowserPreviewService};
121
122#[cfg(feature = "llm")]
123pub use llm_extractor::{LLMExtractor, LLMExtractorConfig, ContentFormat, ProcessedContent, ExtractionResult, LLMProvider, TokenUsage};
124#[cfg(feature = "llm")]
125pub use llm_providers::MockProvider;
126#[cfg(feature = "llm")]
127pub use llm_providers::openai::OpenAIProvider;
128#[cfg(feature = "llm")]
129pub use llm_providers::anthropic::AnthropicProvider;
130#[cfg(feature = "llm")]
131pub use llm_providers::claude_compat::ClaudeCompatProvider;
132#[cfg(all(feature = "llm", feature = "cc-sdk"))]
133pub use llm_providers::claude_code::ClaudeCodeProvider;
134#[cfg(feature = "llm")]
135pub use llm_providers::LocalProvider;
136#[cfg(feature = "llm")]
137pub use llm_config::{ApiKeyValidator, LLMConfig};
138
139#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
140pub struct Preview {
141 pub url: String,
142 pub title: Option<String>,
143 pub description: Option<String>,
144 pub image_url: Option<String>,
145 pub favicon: Option<String>,
146 pub site_name: Option<String>,
147}
148
149#[async_trait]
150pub trait PreviewGenerator {
151 async fn generate_preview(&self, url: &str) -> Result<Preview, PreviewError>;
152}
153
154#[cfg(feature = "twitter")]
155pub fn is_twitter_url(url: &str) -> bool {
156 url.contains("twitter.com") || url.contains("x.com")
157}
158
159#[cfg(not(feature = "twitter"))]
160pub fn is_twitter_url(_url: &str) -> bool {
161 false
162}