wf_market/lib.rs
1//! # wf-market
2//!
3//! A Rust client library for the [warframe.market](https://warframe.market) API.
4//!
5//! This library provides a type-safe, async client for interacting with the
6//! warframe.market trading platform, including both HTTP REST API and WebSocket
7//! real-time updates.
8//!
9//! ## Features
10//!
11//! - **Type-safe API**: Compile-time guarantees prevent common mistakes
12//! - **Async/await**: Built on Tokio for efficient async operations
13//! - **Session persistence**: Save and restore login sessions
14//! - **Rate limiting**: Built-in rate limiter to prevent API throttling
15//! - **Caching**: Optional caching for slowly-changing data
16//! - **WebSocket support**: Real-time updates (optional feature)
17//!
18//! ## Quick Start
19//!
20//! ```ignore
21//! use wf_market::{Client, Credentials, CreateOrder};
22//!
23//! #[tokio::main]
24//! async fn main() -> wf_market::Result<()> {
25//! // Create a client (fetches items automatically)
26//! let client = Client::builder().build().await?;
27//!
28//! // Items are pre-loaded and accessible via client.items()
29//! println!("Loaded {} items", client.items().len());
30//!
31//! // Get orders for an item
32//! let orders = client.get_orders("nikana_prime_set").await?;
33//! for order in orders.iter().take(5) {
34//! // Item info is automatically available on orders
35//! if let Some(item) = order.get_item() {
36//! println!("{}: {} @ {}p", order.user.ingame_name, item.name(), order.platinum);
37//! }
38//! }
39//!
40//! // Login for authenticated operations
41//! let creds = Credentials::new(
42//! "your@email.com",
43//! "password",
44//! Credentials::generate_device_id(),
45//! );
46//! let client = client.login(creds).await?;
47//!
48//! // Create an order
49//! let order = client.create_order(
50//! CreateOrder::sell("nikana_prime_set", 100, 1)
51//! ).await?;
52//! println!("Created order: {}", order.id());
53//!
54//! Ok(())
55//! }
56//! ```
57//!
58//! ## Session Persistence
59//!
60//! Save and restore login sessions to avoid re-authenticating:
61//!
62//! ```ignore
63//! use wf_market::{Client, Credentials};
64//!
65//! async fn example() -> wf_market::Result<()> {
66//! // Initial login
67//! let creds = Credentials::new("email", "password", Credentials::generate_device_id());
68//! let client = Client::from_credentials(creds).await?;
69//!
70//! // Save session
71//! let session = client.export_session();
72//! let json = serde_json::to_string(&session)?;
73//! std::fs::write("session.json", &json)?;
74//!
75//! // Later: restore session
76//! let saved: Credentials = serde_json::from_str(&std::fs::read_to_string("session.json")?)?;
77//!
78//! // Validate before using (recommended)
79//! if Client::validate_credentials(&saved).await? {
80//! let client = Client::from_credentials(saved).await?;
81//! }
82//!
83//! Ok(())
84//! }
85//! ```
86//!
87//! ## Caching
88//!
89//! Use the [`ApiCache`] to persist items across application restarts:
90//!
91//! ```ignore
92//! use wf_market::{Client, ApiCache, SerializableCache};
93//!
94//! async fn example() -> wf_market::Result<()> {
95//! // Load cache from disk (or create new)
96//! let mut cache = match std::fs::read_to_string("cache.json") {
97//! Ok(json) => serde_json::from_str::<SerializableCache>(&json)?
98//! .into_api_cache(),
99//! Err(_) => ApiCache::new(),
100//! };
101//!
102//! // Build client using cache (uses cached items if < 1 day old)
103//! let client = Client::builder()
104//! .build_with_cache(&mut cache)
105//! .await?;
106//!
107//! // Items are loaded from cache or API
108//! println!("Loaded {} items", client.items().len());
109//!
110//! // Save cache for next time
111//! let serializable = SerializableCache::from(&cache);
112//! std::fs::write("cache.json", serde_json::to_string(&serializable)?)?;
113//!
114//! Ok(())
115//! }
116//! ```
117//!
118//! ## WebSocket (Real-time Updates)
119//!
120//! Enable the `websocket` feature for real-time order updates:
121//!
122//! ```toml
123//! [dependencies]
124//! wf-market = { version = "0.2", features = ["websocket"] }
125//! ```
126//!
127//! ```ignore
128//! use wf_market::{Client, Credentials};
129//! use wf_market::ws::{WsEvent, Subscription};
130//!
131//! async fn example() -> wf_market::Result<()> {
132//! let client = Client::from_credentials(/* ... */).await?;
133//!
134//! let ws = client.websocket()
135//! .on_event(|event| async move {
136//! match event {
137//! WsEvent::OnlineCount { authorized, .. } => {
138//! println!("Users online: {}", authorized);
139//! }
140//! WsEvent::OrderCreated { order } => {
141//! println!("New order: {}p", order.platinum);
142//! }
143//! _ => {}
144//! }
145//! })
146//! .subscribe(Subscription::all_new_orders())
147//! .connect()
148//! .await?;
149//!
150//! Ok(())
151//! }
152//! ```
153//!
154//! ## Feature Flags
155//!
156//! - `default` = `["rustls-tls"]`
157//! - `rustls-tls`: Use rustls for TLS (default)
158//! - `native-tls`: Use native TLS instead of rustls
159//! - `websocket`: Enable WebSocket support for real-time updates
160//! - `v1-api`: Enable deprecated V1 API endpoints (statistics)
161
162// Modules
163mod api;
164pub mod cache;
165pub mod client;
166pub mod error;
167mod internal;
168pub mod models;
169
170#[cfg(feature = "websocket")]
171pub mod ws;
172
173// Re-exports for convenience
174pub use cache::{ApiCache, CachedItems, CachedRivens, SerializableCache};
175pub use client::{AuthState, Authenticated, Client, ClientBuilder, ClientConfig, Unauthenticated};
176pub use error::{ApiErrorDetails, ApiErrorResponse, Error, Result};
177
178#[cfg(feature = "websocket")]
179pub use error::WsError;
180
181// Model re-exports
182pub use models::{
183 // Users
184 Achievement,
185 AchievementType,
186 // Common types
187 Activity,
188 ActivityType,
189 // Orders
190 CreateOrder,
191 // Auth
192 Credentials,
193 FullUser,
194 // Items
195 Item,
196 ItemIndex,
197 ItemSet,
198 ItemTranslation,
199 Language,
200 ModView,
201 Order,
202 OrderListing,
203 OrderType,
204 OwnedOrder,
205 OwnedOrderId,
206 Platform,
207 Rarity,
208 // Rivens
209 Riven,
210 RivenAttribute,
211 RivenAttributeTranslation,
212 RivenTranslation,
213 RivenType,
214 SculptureView,
215 SubscriptionTier,
216 Theme,
217 TopOrderFilters,
218 TopOrders,
219 // Transactions
220 Transaction,
221 UpdateOrder,
222 UpdateProfile,
223 User,
224 UserPrivate,
225 UserProfile,
226 UserRole,
227 UserStatus,
228 WithPassword,
229};
230
231// V1 API model re-exports (deprecated, feature-gated)
232#[cfg(feature = "v1-api")]
233pub use models::{ItemStatistics, StatisticEntry, TimeframedStatistics};