techne-sdk 0.3.8

TechneSDK's logic written once: version ranking (eventState) and offline record verification over the published check, shipped to TypeScript as WebAssembly; with opt-in atproto plumbing (service auth, DID resolution, signed labels, proven record fetches, PDS password sessions) behind the `crypto` and `net` features.
Documentation
//! The platform's NSID rename map, dated (`inputs/platform-api/nsid_renames.json`, the same bytes the
//! check embeds). The check answers [`techne_lexicon_check::current_name`] undated (a signed body keeps
//! its names for as long as it lives) and exposes no list, so the crate carries the map's bytes itself
//! (`nsid_renames.json` next to this file, so `cargo package` has it; `put`'s
//! `renames_copy_is_the_platforms` holds it to the input and to the check).
//!
//! The dates are the platform's: each pair is honoured through its own last day, `deleteAfter`, unless
//! `closeEarlier` lists its old name under an earlier date.
use serde_json::Value;

pub(crate) const JSON: &str = include_str!("nsid_renames.json");

pub(crate) struct Pair {
    pub(crate) old: String,
    pub(crate) new: String,
    /// The first unix second (00:00 UTC) the pair is no longer honoured: the day after its last day.
    closes_at: i64,
}

/// Every pair in the map, dated.
pub(crate) fn pairs() -> &'static [Pair] {
    static PAIRS: std::sync::OnceLock<Vec<Pair>> = std::sync::OnceLock::new();
    PAIRS.get_or_init(|| {
        let doc: Value = serde_json::from_str(JSON).expect("the rename map is JSON");
        let day = |d: &str| {
            let date = chrono::NaiveDate::parse_from_str(d, "%Y-%m-%d").expect("the rename map's dates are YYYY-MM-DD");
            (date + chrono::Days::new(1)).and_hms_opt(0, 0, 0).expect("midnight").and_utc().timestamp()
        };
        let delete_after = day(doc["deleteAfter"].as_str().expect("the rename map has a deleteAfter"));
        let early = |old: &str| {
            doc["closeEarlier"].as_object().into_iter().flatten().find_map(|(d, olds)| {
                olds.as_array().is_some_and(|a| a.iter().any(|o| o == old)).then(|| day(d))
            })
        };
        doc["renames"]
            .as_object()
            .expect("the rename map has a renames object")
            .iter()
            .map(|(old, new)| Pair {
                old: old.clone(),
                new: new.as_str().expect("the rename map's new names are strings").to_owned(),
                closes_at: early(old).unwrap_or(delete_after),
            })
            .collect()
    })
}

/// The name `old` was renamed to while the platform still honours the pair at `now_unix` (through its
/// last day, UTC); `None` from the day after, and for a name that is not an old name. One hop, as the
/// platform's `regenos_lexicons::nsid::current_name(name, today)`.
pub(crate) fn current_name_at(old: &str, now_unix: u64) -> Option<&'static str> {
    let p = pairs().iter().find(|p| p.old == old)?;
    (i64::try_from(now_unix).ok()? < p.closes_at).then_some(p.new.as_str())
}