Skip to main content

systemprompt_provider_contracts/
sitemap.rs

1//! [`SitemapProvider`] contract for emitting sitemap URL entries.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use async_trait::async_trait;
7use std::collections::HashMap;
8use systemprompt_identifiers::{LocaleCode, SourceId};
9
10use crate::error::ProviderResult;
11
12#[derive(Debug)]
13pub struct SitemapContext<'a> {
14    pub base_url: &'a str,
15    pub source_name: &'a str,
16}
17
18#[derive(Debug, Clone)]
19pub struct SitemapAlternate {
20    pub hreflang: LocaleCode,
21    pub href: String,
22}
23
24#[derive(Debug, Clone)]
25pub struct SitemapUrlEntry {
26    pub loc: String,
27    pub lastmod: String,
28    pub changefreq: String,
29    pub priority: f32,
30    pub alternates: Vec<SitemapAlternate>,
31}
32
33#[derive(Debug, Clone)]
34pub struct PlaceholderMapping {
35    pub placeholder: String,
36    pub field: String,
37}
38
39#[derive(Debug, Clone)]
40pub struct SitemapSourceSpec {
41    pub source_id: SourceId,
42    pub url_pattern: String,
43    pub placeholders: Vec<PlaceholderMapping>,
44    pub priority: f32,
45    pub changefreq: String,
46}
47
48// Why: provider is consumed as a trait object by the generator crate; an
49// async fn in a bare trait is not dyn-compatible, so #[async_trait] is
50// required.
51#[async_trait]
52pub trait SitemapProvider: Send + Sync {
53    fn provider_id(&self) -> &'static str;
54
55    fn source_specs(&self) -> Vec<SitemapSourceSpec> {
56        vec![]
57    }
58
59    fn static_urls(&self, _base_url: &str) -> Vec<SitemapUrlEntry> {
60        vec![]
61    }
62
63    // JSON: `content` is a polymorphic per-source content object (markdown
64    // frontmatter, blog row, etc.) consumed by the provider to fill
65    // placeholders in the URL pattern. Defining a typed enum here would force
66    // every consumer into a tagged union; trait boundary input.
67    async fn resolve_placeholders(
68        &self,
69        ctx: &SitemapContext<'_>,
70        content: &serde_json::Value,
71        placeholders: &[PlaceholderMapping],
72    ) -> ProviderResult<HashMap<String, String>>;
73
74    fn priority(&self) -> u32 {
75        100
76    }
77}