freighter_api_types/index/
mod.rs

1use async_trait::async_trait;
2use semver::Version;
3use std::future::Future;
4use std::pin::Pin;
5
6use request::{ListQuery, Publish, PublishDependency};
7use response::{CompletedPublication, CrateVersion, ListAll, SearchResults};
8
9#[cfg(any(feature = "index", feature = "server", feature = "client"))]
10use serde::{Deserialize, Serialize};
11
12pub mod request;
13pub mod response;
14
15mod error;
16pub use error::*;
17
18pub type IndexResult<T> = Result<T, IndexError>;
19
20#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
21#[cfg_attr(
22    any(feature = "index", feature = "server", feature = "client"),
23    derive(Serialize, Deserialize),
24    serde(rename_all = "lowercase")
25)]
26#[cfg_attr(
27    feature = "postgres",
28    derive(postgres_types::ToSql, postgres_types::FromSql),
29    postgres(name = "dependency_kind")
30)]
31pub enum DependencyKind {
32    #[cfg_attr(feature = "postgres", postgres(name = "normal"))]
33    #[default]
34    Normal,
35    #[cfg_attr(feature = "postgres", postgres(name = "dev"))]
36    Dev,
37    #[cfg_attr(feature = "postgres", postgres(name = "build"))]
38    Build,
39}
40
41impl From<response::CrateVersion> for request::Publish {
42    fn from(value: CrateVersion) -> Self {
43        Self {
44            name: value.name,
45            vers: value.vers,
46            deps: value
47                .deps
48                .into_iter()
49                .map(|x| PublishDependency {
50                    name: x.name,
51                    version_req: x.req,
52                    features: x.features,
53                    optional: x.optional,
54                    default_features: x.default_features,
55                    target: x.target,
56                    kind: x.kind,
57                    registry: x.registry,
58                    explicit_name_in_toml: x.package,
59                })
60                .collect(),
61            features: value.features,
62            // Note: We do not carry over authors since its not in index
63            authors: Vec::new(),
64            description: None,
65            documentation: None,
66            homepage: None,
67            readme: None,
68            readme_file: None,
69            keywords: vec![],
70            categories: vec![],
71            license: None,
72            license_file: None,
73            repository: None,
74            badges: None,
75            links: None,
76        }
77    }
78}
79
80/// A client for talking with a backing index database or storage medium.
81///
82/// Operations performed via this client MUST be atomic.
83/// In the event of a conflict, [`IndexError::Conflict`] should be returned by an operation.
84///
85/// # Note
86/// The index client does NOT authenticate user actions.
87/// User actions should be authenticated before an operation is performed.
88#[async_trait]
89pub trait IndexProvider: Sync {
90    type Config;
91
92    async fn healthcheck(&self) -> anyhow::Result<()>;
93
94    /// Get the sparse index entry for a crate.
95    ///
96    /// If successful, a [`CrateVersion`] api object will be returned.
97    ///
98    /// If the crate could not be found in the index, [`None`] will be returned.
99    ///
100    /// If an error occurs while trying to generate the sparse entry, [`IndexError::ServiceError`]
101    /// will be returned.
102    async fn get_sparse_entry(&self, crate_name: &str) -> IndexResult<Vec<CrateVersion>>;
103    /// Confirm that a particular crate and version pair exists, and return its yank status
104    async fn confirm_existence(&self, crate_name: &str, version: &Version) -> IndexResult<bool>;
105    /// Yank a crate version.
106    async fn yank_crate(&self, crate_name: &str, version: &Version) -> IndexResult<()>;
107    /// Unyank a crate version
108    async fn unyank_crate(&self, crate_name: &str, version: &Version) -> IndexResult<()>;
109    /// Search the index for crates satisfying a query string, returning up to `limit` results.
110    ///
111    /// The syntax and semantics of the search are up to the implementation to define.
112    async fn search(&self, query_string: &str, limit: usize) -> IndexResult<SearchResults>;
113    /// Publish a crate version.
114    ///
115    /// `end_step` is a future to run after the crate has been submitted to the index, but before
116    /// any transactional commits have occurred.
117    /// If it fails, the operation MUST be rolled back.
118    async fn publish(
119        &self,
120        version: &Publish,
121        checksum: &str,
122        end_step: Pin<&mut (dyn Future<Output = IndexResult<()>> + Send)>,
123    ) -> IndexResult<CompletedPublication>;
124    /// List crates in the index, optionally specifying pagination.
125    ///
126    /// If no pagination is provided, all crates should be returned.
127    async fn list(&self, pagination: &ListQuery) -> IndexResult<ListAll>;
128}