egs_api/facade/store.rs
1use crate::EpicGames;
2use crate::api::error::EpicAPIError;
3use crate::api::types::asset_info::AssetInfo;
4use crate::api::types::billing_account::BillingAccount;
5use crate::api::types::catalog_item::CatalogItemPage;
6use crate::api::types::catalog_offer::CatalogOfferPage;
7use crate::api::types::currency::CurrencyPage;
8use crate::api::types::price::PriceResponse;
9use crate::api::types::quick_purchase::QuickPurchaseResponse;
10use crate::api::types::uplay::{
11 UplayClaimResult, UplayCodesResult, UplayGraphQLResponse, UplayRedeemResult,
12};
13
14impl EpicGames {
15 /// Like [`catalog_items`](Self::catalog_items), but returns a `Result` instead of swallowing errors.
16 pub async fn try_catalog_items(
17 &self,
18 namespace: &str,
19 start: i64,
20 count: i64,
21 ) -> Result<CatalogItemPage, EpicAPIError> {
22 self.egs.catalog_items(namespace, start, count).await
23 }
24
25 /// Fetch paginated catalog items for a namespace.
26 ///
27 /// Queries the Epic catalog service for items within a given namespace
28 /// (e.g., a game's namespace). Results are paginated — use `start` and
29 /// `count` to page through. Each [`CatalogItemPage`] includes a `paging`
30 /// field with the total count.
31 ///
32 /// Returns `None` on API errors.
33 pub async fn catalog_items(
34 &self,
35 namespace: &str,
36 start: i64,
37 count: i64,
38 ) -> Option<CatalogItemPage> {
39 self.try_catalog_items(namespace, start, count).await.ok()
40 }
41
42 /// Like [`catalog_offers`](Self::catalog_offers), but returns a `Result` instead of swallowing errors.
43 pub async fn try_catalog_offers(
44 &self,
45 namespace: &str,
46 start: i64,
47 count: i64,
48 ) -> Result<CatalogOfferPage, EpicAPIError> {
49 self.egs.catalog_offers(namespace, start, count).await
50 }
51
52 /// Fetch paginated catalog offers for a namespace.
53 ///
54 /// Queries the Epic catalog service for offers (purchasable items) within
55 /// a namespace. Offers include pricing metadata, seller info, and linked
56 /// catalog items. Use `start` and `count` to paginate.
57 ///
58 /// Returns `None` on API errors.
59 pub async fn catalog_offers(
60 &self,
61 namespace: &str,
62 start: i64,
63 count: i64,
64 ) -> Option<CatalogOfferPage> {
65 self.try_catalog_offers(namespace, start, count).await.ok()
66 }
67
68 /// Like [`bulk_catalog_items`](Self::bulk_catalog_items), but returns a `Result` instead of swallowing errors.
69 pub async fn try_bulk_catalog_items(
70 &self,
71 items: &[(&str, &str)],
72 ) -> Result<
73 std::collections::HashMap<String, std::collections::HashMap<String, AssetInfo>>,
74 EpicAPIError,
75 > {
76 self.egs.bulk_catalog_items(items).await
77 }
78
79 /// Bulk fetch catalog items across multiple namespaces.
80 ///
81 /// Accepts a slice of `(namespace, item_id)` pairs and returns them grouped
82 /// by namespace → item_id → [`AssetInfo`]. Useful for resolving catalog
83 /// metadata for items from different games in a single request.
84 ///
85 /// Returns `None` on API errors.
86 pub async fn bulk_catalog_items(
87 &self,
88 items: &[(&str, &str)],
89 ) -> Option<std::collections::HashMap<String, std::collections::HashMap<String, AssetInfo>>>
90 {
91 self.try_bulk_catalog_items(items).await.ok()
92 }
93
94 /// Like [`currencies`](Self::currencies), but returns a `Result` instead of swallowing errors.
95 pub async fn try_currencies(
96 &self,
97 start: i64,
98 count: i64,
99 ) -> Result<CurrencyPage, EpicAPIError> {
100 self.egs.currencies(start, count).await
101 }
102
103 /// Fetch available currencies from the Epic catalog.
104 ///
105 /// Returns paginated currency definitions including code, symbol, and
106 /// decimal precision. Use `start` and `count` to paginate.
107 ///
108 /// Returns `None` on API errors.
109 pub async fn currencies(&self, start: i64, count: i64) -> Option<CurrencyPage> {
110 self.try_currencies(start, count).await.ok()
111 }
112
113 /// Like [`library_state_token_status`](Self::library_state_token_status), but returns a `Result` instead of swallowing errors.
114 pub async fn try_library_state_token_status(
115 &self,
116 token_id: &str,
117 ) -> Result<bool, EpicAPIError> {
118 self.egs.library_state_token_status(token_id).await
119 }
120
121 /// Check the validity of a library state token.
122 ///
123 /// Returns `Some(true)` if the token is still valid, `Some(false)` if
124 /// expired or invalid, or `None` on API errors. Library state tokens are
125 /// used to detect changes to the user's library since the last sync.
126 ///
127 /// Returns `None` on API errors.
128 pub async fn library_state_token_status(&self, token_id: &str) -> Option<bool> {
129 self.try_library_state_token_status(token_id).await.ok()
130 }
131
132 /// Like [`offer_prices`](Self::offer_prices), but returns a `Result` instead of swallowing errors.
133 pub async fn try_offer_prices(
134 &self,
135 namespace: &str,
136 offer_ids: &[String],
137 country: &str,
138 ) -> Result<PriceResponse, EpicAPIError> {
139 self.egs.offer_prices(namespace, offer_ids, country).await
140 }
141
142 /// Fetch offer prices from Epic's price engine.
143 ///
144 /// Queries current pricing for one or more offers within a namespace,
145 /// localized to a specific country. The response includes original price,
146 /// discount price, and pre-formatted display strings.
147 ///
148 /// Returns `None` on API errors.
149 pub async fn offer_prices(
150 &self,
151 namespace: &str,
152 offer_ids: &[String],
153 country: &str,
154 ) -> Option<PriceResponse> {
155 self.try_offer_prices(namespace, offer_ids, country)
156 .await
157 .ok()
158 }
159
160 /// Like [`quick_purchase`](Self::quick_purchase), but returns a `Result` instead of swallowing errors.
161 pub async fn try_quick_purchase(
162 &self,
163 namespace: &str,
164 offer_id: &str,
165 ) -> Result<QuickPurchaseResponse, EpicAPIError> {
166 self.egs.quick_purchase(namespace, offer_id).await
167 }
168
169 /// Execute a quick purchase (typically for free game claims).
170 ///
171 /// Initiates a purchase order for a free offer. The response contains the
172 /// order ID and its processing status. For paid offers, use the full
173 /// checkout flow in the Epic Games launcher instead.
174 ///
175 /// Returns `None` on API errors.
176 pub async fn quick_purchase(
177 &self,
178 namespace: &str,
179 offer_id: &str,
180 ) -> Option<QuickPurchaseResponse> {
181 self.try_quick_purchase(namespace, offer_id).await.ok()
182 }
183
184 /// Like [`billing_account`](Self::billing_account), but returns a `Result` instead of swallowing errors.
185 pub async fn try_billing_account(&self) -> Result<BillingAccount, EpicAPIError> {
186 self.egs.billing_account().await
187 }
188
189 /// Fetch the default billing account for payment processing.
190 ///
191 /// Returns the account's billing country, which is used to determine
192 /// regional pricing and payment availability.
193 ///
194 /// Returns `None` on API errors.
195 pub async fn billing_account(&self) -> Option<BillingAccount> {
196 self.try_billing_account().await.ok()
197 }
198
199 // ── Uplay / Ubisoft Store ──
200
201 /// Fetch Uplay codes linked to the user's Epic account.
202 pub async fn store_get_uplay_codes(
203 &self,
204 ) -> Result<UplayGraphQLResponse<UplayCodesResult>, EpicAPIError> {
205 self.egs.store_get_uplay_codes().await
206 }
207
208 /// Claim a Uplay code for a specific game.
209 pub async fn store_claim_uplay_code(
210 &self,
211 uplay_account_id: &str,
212 game_id: &str,
213 ) -> Result<UplayGraphQLResponse<UplayClaimResult>, EpicAPIError> {
214 self.egs
215 .store_claim_uplay_code(uplay_account_id, game_id)
216 .await
217 }
218
219 /// Redeem all pending Uplay codes for the user's account.
220 pub async fn store_redeem_uplay_codes(
221 &self,
222 uplay_account_id: &str,
223 ) -> Result<UplayGraphQLResponse<UplayRedeemResult>, EpicAPIError> {
224 self.egs.store_redeem_uplay_codes(uplay_account_id).await
225 }
226}