Skip to main content

monetize_embed/
sold.rs

1//! **What a sold private Gunnar is called** — ONE function, called by the shop
2//! that sells it (monetize's estate order: the ready mail's first-login link,
3//! the DNS records, `laid.json`'s `names`) and by the kit that installs it
4//! (its certificate, its passkeys' relying party, its DNS records).
5//!
6//! A sold estate lives under the SELLING shop's apex (owner, 2026-10-08):
7//! gunnar.rs sells `acme.gunnar.rs`; test2's shop sells `acme.test2.gunnar.rs`
8//! — the certificate, the passkey RP, the DNS, the link, the mail and
9//! `laid.json` all say the same name. Wiring trace A43: monetize named it
10//! `<co>.<apex>` while the kit named it `<co>.gunnar.rs` whatever the apex, so
11//! a test2 buyer's first-login link led to a name nothing served.
12
13/// The names of one sold estate. `host` first: it is the console, the passkeys'
14/// relying party, the name the certificate is for.
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct SoldNames {
17    pub company: String,
18    pub apex: String,
19    /// `<company>.<apex>`.
20    pub host: String,
21}
22
23impl SoldNames {
24    /// The names of `company` sold by the shop at `apex` (`gunnar.rs`,
25    /// `test2.gunnar.rs`). Pure; neither is checked here (the shop's name rule
26    /// and the kit's are).
27    pub fn of(company: &str, apex: &str) -> SoldNames {
28        let (company, apex) = (company.trim().to_string(), apex.trim().trim_end_matches('.').to_ascii_lowercase());
29        let host = format!("{company}.{apex}");
30        SoldNames { company, apex, host }
31    }
32
33    /// **Every name the estate serves under the shop's apex**, the kit's
34    /// `subzone` shape: `<host>`, `www.<host>`, `git.<host>` — each one an A
35    /// record to its front. No `monetize.<host>` (G16, ONE monetize): a sold
36    /// estate runs no monetize; its boxes pull from the ONE.
37    pub fn names(&self) -> Vec<String> {
38        ["", "www.", "git."].iter().map(|p| format!("{p}{}", self.host)).collect()
39    }
40
41    /// **The word the kit puts between a name's first label and its DNS zone**
42    /// (`zone` = `gunnar.rs`): `acme` at gunnar.rs, `acme.test2` at
43    /// test2.gunnar.rs — so `git.gunnar.rs` becomes `git.acme.test2.gunnar.rs`.
44    /// `None` when the host is not inside `zone` (the kit cannot write it).
45    pub fn word_in(&self, zone: &str) -> Option<String> {
46        let zone = zone.trim().trim_end_matches('.').to_ascii_lowercase();
47        self.host.strip_suffix(&format!(".{zone}")).filter(|w| !w.is_empty()).map(str::to_string)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    /// ★ A43: the shop and the kit name a sold estate under the SELLING shop's apex.
56    #[test]
57    fn a_sold_estate_is_named_under_the_selling_shops_apex() {
58        let rs = SoldNames::of("acme", "gunnar.rs");
59        // G16 (ONE monetize): a sold estate runs no monetize, so it serves no `monetize.<host>`.
60        assert_eq!(rs.names(), vec!["acme.gunnar.rs", "www.acme.gunnar.rs", "git.acme.gunnar.rs"]);
61        assert_eq!(rs.word_in("gunnar.rs").as_deref(), Some("acme"));
62        let t2 = SoldNames::of("acme", "test2.gunnar.rs");
63        assert_eq!(t2.host, "acme.test2.gunnar.rs");
64        assert_eq!(t2.names(), vec!["acme.test2.gunnar.rs", "www.acme.test2.gunnar.rs", "git.acme.test2.gunnar.rs"]);
65        assert_eq!(t2.word_in("gunnar.rs").as_deref(), Some("acme.test2"));
66        assert_eq!(t2.word_in("vetra.se"), None, "a host outside the zone has no word in it");
67        assert_eq!(SoldNames::of("acme", "Test2.Gunnar.RS.").host, "acme.test2.gunnar.rs");
68    }
69}