Something went wrong. Try again.
karitham.dev website! atproto & fancy ssg + csr & blog articles karitham.dev
atproto gleam blog nix
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164import atproto.{type DecodedRecord, DecodedRecord}import decodeimport encodeimport gen/actor/defs.{type ProfileViewDetailed, ProfileViewDetailed}import gen/feed/play.{type FeedPlay, ArtistView, FeedPlay}import gen/repo.{type Repo, Repo}import gleam/dictimport gleam/option.{None, Some}import gleam/stringimport gleeunit/shouldimport hydration.{HydrationModel}
fn sample_profile() -> ProfileViewDetailed { ProfileViewDetailed( did: "did:plc:test", handle: "test.bsky.social", display_name: Some("Test User"), description: Some("round-trip"), avatar: Some("https://example.com/avatar.jpg"), banner: Some("https://example.com/banner.jpg"), followers_count: Some(100), follows_count: Some(50), posts_count: Some(25), pronouns: Some("they/them"), )}
fn sample_plays() -> List(FeedPlay) { [ FeedPlay( track_name: "Track A", artists: [ ArtistView(artist_name: "Artist 1", artist_mb_id: Some("mbid-1")), ArtistView(artist_name: "Artist 2", artist_mb_id: Some("")), ], release_name: Some("Album A"), duration: Some(180), played_time: "2026-07-18T10:00:00Z", origin_uri: Some("https://example.com/a"), ), FeedPlay( track_name: "Track B", artists: [ ArtistView(artist_name: "Solo", artist_mb_id: Some("mbid-solo")), ], release_name: None, duration: None, played_time: "2026-07-18T11:00:00Z", origin_uri: None, ), ]}
fn sample_repos() -> List(DecodedRecord(Repo)) { [ DecodedRecord( uri: "at://did:plc:one/sh.tangled.repo/repo-one", cid: "bafy1", value: Repo( name: Some("repo-one"), description: Some("first"), repo_did: "did:plc:one", created_at: "2026-01-01T00:00:00Z", topics: Some(["gleam", "atproto"]), website: None, ), ), DecodedRecord( uri: "at://did:plc:two/sh.tangled.repo/repo-two", cid: "bafy2", value: Repo( name: Some("repo-two"), description: Some(""), repo_did: "did:plc:two", created_at: "2026-02-01T00:00:00Z", topics: Some([]), website: None, ), ), ]}
pub fn round_trip_full_model_test() { let original = HydrationModel( profile: sample_profile(), plays: sample_plays(), repos: sample_repos(), rewrites: dict.from_list([ #("https://cdn.example/avatar.jpg", "/img/profile/avatar.jpeg"), ]), )
let json = encode.encode_hydration_model(original) let result = decode.decode_hydration_model(json) let assert Ok(decoded) = result decoded.profile |> should.equal(original.profile) decoded.plays |> should.equal(original.plays) decoded.repos |> should.equal(original.repos) decoded.rewrites |> should.equal(original.rewrites)}
pub fn round_trip_empty_lists_test() { let original = HydrationModel( profile: sample_profile(), plays: [], repos: [], rewrites: dict.new(), ) let json = encode.encode_hydration_model(original) let assert Ok(decoded) = decode.decode_hydration_model(json) decoded.plays |> should.equal([]) decoded.repos |> should.equal([]) decoded.rewrites |> should.equal(dict.new())}
pub fn script_safe_escaping_test() { let hostile = ProfileViewDetailed( did: "did:plc:xss", handle: "xss.test", display_name: Some("</script><script>alert(1)</script>"), description: Some("a & b < c > d"), avatar: Some("https://example.com/avatar.jpg"), banner: Some("https://example.com/banner.jpg"), followers_count: Some(1), follows_count: Some(1), posts_count: Some(1), pronouns: None, ) let original = HydrationModel(profile: hostile, plays: [], repos: [], rewrites: dict.new())
let json = encode.encode_hydration_model(original) // Raw `</script>` would terminate the embedding script tag. json |> string.contains("</script>") |> should.be_false() json |> string.contains("\\u003c/script\\u003e") |> should.be_true() // The escapes are lossless for the JSON decoder. let assert Ok(decoded) = decode.decode_hydration_model(json) decoded.profile |> should.equal(hostile)}
pub fn round_trip_zero_counts_test() { let profile = ProfileViewDetailed( did: "did:plc:zero", handle: "zero.test", display_name: Some(""), description: Some(""), avatar: Some(""), banner: Some(""), followers_count: Some(0), follows_count: Some(0), posts_count: Some(0), pronouns: None, ) let original = HydrationModel(profile: profile, plays: [], repos: [], rewrites: dict.new()) let json = encode.encode_hydration_model(original) let assert Ok(decoded) = decode.decode_hydration_model(json) decoded.profile |> should.equal(profile)}