1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Client for browsing the Apify Store (`/v2/store`).
use crate::clients::base::{list_resource, ResourceContext};
use crate::clients::pagination::{list_iterator, ListIterator};
use crate::common::{PaginationList, QueryParams};
use crate::error::ApifyClientResult;
use crate::http_client::HttpClient;
use crate::models::ActorStoreListItem;
/// A lazy, page-fetching iterator over Apify Store Actors.
///
/// Returned by [`StoreCollectionClient::iterate`]. This is an alias for the shared
/// [`ListIterator`]; call its `next()` to yield one Actor at a time, fetching further pages
/// from the API transparently until the listing is exhausted.
pub type StoreActorIterator = ListIterator<ActorStoreListItem>;
/// Options for searching the Apify Store.
#[derive(Debug, Default, Clone)]
pub struct StoreListOptions {
/// Number of items to skip.
pub offset: Option<i64>,
/// Item limit. Its meaning depends on the method: for [`StoreCollectionClient::list`] it is a
/// single page's size (the maximum items that one call returns); for
/// [`StoreCollectionClient::iterate`] it is a cap on the *total* number of items yielded across
/// all pages. See each method's docs.
pub limit: Option<i64>,
/// Full-text search query.
pub search: Option<String>,
/// Sort key (e.g. `popularity`, `newest`).
pub sort_by: Option<String>,
/// Filter by category.
pub category: Option<String>,
/// Filter by owner username.
pub username: Option<String>,
/// Filter by pricing model.
pub pricing_model: Option<String>,
/// Include Actors that the current user cannot run (e.g. needing a missing integration).
pub include_unrunnable_actors: Option<bool>,
/// Filter to Actors that allow agentic (x402/Skyfire) users.
pub allows_agentic_users: Option<bool>,
/// Response format requested from the API (e.g. `json`).
pub response_format: Option<String>,
}
/// Client for the Apify Store.
#[derive(Debug, Clone)]
pub struct StoreCollectionClient {
ctx: ResourceContext,
}
impl StoreCollectionClient {
pub(crate) fn new(http: HttpClient, base_url: &str) -> Self {
Self {
ctx: ResourceContext::collection(http, base_url, "store"),
}
}
/// Lists Actors from the Apify Store matching the given options.
///
/// Awaiting once returns a single page; use [`StoreCollectionClient::iterate`] to lazily
/// iterate across pages.
pub async fn list(
&self,
options: StoreListOptions,
) -> ApifyClientResult<PaginationList<ActorStoreListItem>> {
let params = self.build_params(&options);
list_resource(&self.ctx, None, ¶ms).await
}
/// Lazily iterates all Store Actors matching `options`, fetching pages on demand.
///
/// Returns a [`StoreActorIterator`] whose `next()` method yields one Actor at a time,
/// transparently fetching subsequent pages.
///
/// `options.limit` caps the *total* number of items yielded across all pages, unlike
/// [`list`](Self::list) where `limit` is a single page's size. Set the per-page fetch size
/// with [`with_chunk_size`](crate::ListIterator::with_chunk_size); see
/// [`ListIterator`] for details.
pub fn iterate(&self, options: StoreListOptions) -> StoreActorIterator {
list_iterator!(self, options, list)
}
fn build_params(&self, options: &StoreListOptions) -> QueryParams {
let mut params = QueryParams::new();
params
.add_int("offset", options.offset)
.add_int("limit", options.limit)
.add_str("search", options.search.clone())
.add_str("sortBy", options.sort_by.clone())
.add_str("category", options.category.clone())
.add_str("username", options.username.clone())
.add_str("pricingModel", options.pricing_model.clone())
.add_bool("includeUnrunnableActors", options.include_unrunnable_actors)
.add_bool("allowsAgenticUsers", options.allows_agentic_users)
.add_str("responseFormat", options.response_format.clone());
params
}
}