From 628d4a17434e6e87f0c8d02304da4862253ce1e0 Mon Sep 17 00:00:00 2001 From: "kacaii.dev" Date: Sun, 12 Jul 2026 17:06:44 -0300 Subject: [PATCH] possum: functions now take the host as a parameter --- CHANGELOG.md | 8 ++ README.md | 40 +++++----- gleam.toml | 4 +- pages/accessing-your-pds.md | 3 +- pages/consulting-your-did.md | 12 ++- src/possum.gleam | 141 +++++++++++++++-------------------- test/possum_test.gleam | 35 +++------ 7 files changed, 104 insertions(+), 139 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea16e97..00afad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v3.0.0 - Unreleased + +### Changed + +- [possum] Functions now take the PDS host as an argument. +- [possum] Most functions now create a new request internally when being called, + there's no need to pipe `request.new()` into them. + ## v2.1.0 - 2026-07-12 ### Added diff --git a/README.md b/README.md index bd22eb8..f934e74 100644 --- a/README.md +++ b/README.md @@ -55,15 +55,15 @@ let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz") let assert Ok(collection) = nsid.parse("sh.tangled.repo") // Reading public data from repositories, no Authorization needed. -request.new() -|> request.set_host("personal.data-server.pds") -|> possum.list_records( - did, - collection:, - limit: option.Some(3), - cursor: option.None, - reverse: option.None, -) +let request = + possum.list_records( + did, + pds: "personal.data-server.pds", + collection:, + limit: option.Some(3), + cursor: option.None, + reverse: option.None, + ) ``` ### Authorized Requests @@ -77,22 +77,20 @@ let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz") // App Passwords can be generated in your Bluesky settings, // It allows authorized access to your PDS. -request.new() -|> request.set_host("personal.data-server.pds") -|> possum.create_session( - did, - app_password: "bsky-app-password", - allow_takendown: option.None, - auth_factor_token: option.None -) +let requests = + possum.create_session( + did, + pds: "personal.data-server.pds", + app_password: "bsky-app-password", + allow_takendown: option.None, + auth_factor_token: option.None + ) // Include header for authorized requests. request.new() -|> request.set_host("personal.data-server.pds") |> possum.authorized("access-token") // Refreshing an authorized Session. -request.new() -|> request.set_host("personal.data-server.pds") -|> possum.refresh_session("refresh-token") +let request = + possum.refresh_session("refresh-token", pds: "personal.data-server.pds") ``` diff --git a/gleam.toml b/gleam.toml index 0c294a2..590cce1 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,7 +1,7 @@ name = "possum" -version = "2.1.0" +version = "3.0.0" -description = "🐀 ATproto library for gleam" +description = "🐀 ATproto library for gleam" licences = ["Apache-2.0"] repository = { type = "tangled", user = "kacaii.dev", repo = "possum" } diff --git a/pages/accessing-your-pds.md b/pages/accessing-your-pds.md index 6917290..200150d 100644 --- a/pages/accessing-your-pds.md +++ b/pages/accessing-your-pds.md @@ -13,8 +13,7 @@ import possum let assert Ok(did) = did.parse("did:plc:z72i7hdynmk6r22z27h6tvur") // Send a request to plc.directory -request.new() -|> possum.get_plc_data(did) +let request = possum.get_plc_data(did) // You can use a decoder like this for your PDS endpoint let decoder = diff --git a/pages/consulting-your-did.md b/pages/consulting-your-did.md index 7cb8ef1..3c3a10f 100644 --- a/pages/consulting-your-did.md +++ b/pages/consulting-your-did.md @@ -17,14 +17,11 @@ handles for them, using the `com.atproto.identity.resolveHandle` endpoint, and don't usually need to implement resolution directly themselves. ```gleam -let assert Ok(handle) = handle.parse("gleam.run") - // You can consult your identifier by sending a request directly to your PDS, // or you can use projects like [Slingshot](https://slingshot.microcosm.blue) // for easy access to cached data when resolving a handle. -request.new() -|> request.set_host("slingshot.microcosm.blue") -|> possum.resolve_handle(handle) +let assert Ok(handle) = handle.parse("gleam.run") +let request = possum.resolve_handle(handle, pds: "slingshot.microcosm.blue") ``` ## HTTPS well-known Method @@ -34,10 +31,11 @@ path `/.well-known/atproto-did.` A valid HTTP response will have an HTTP success status (2xx) and include the DID as the HTTP body with no prefix or wrapper formatting. ```gleam +import possum + // You also verify your DID without DNS by sending a request to `/.well-know/atproto-did` // Your server can then respond with the DID value as plain text. // // The response Content-Type header does not need to be strictly verified. -request.new() -|> possum.resolve_well_known_did("gleam.run") +let request = possum.resolve_well_known_did(host: "gleam.run") ``` diff --git a/src/possum.gleam b/src/possum.gleam index 18dc18d..ef9e413 100644 --- a/src/possum.gleam +++ b/src/possum.gleam @@ -66,10 +66,7 @@ const com_atproto_sync = "xrpc/com.atproto.sync" /// import possum /// /// let assert Ok(did) = did.parse("did:plc:z72i7hdynmk6r22z27h6tvur") -/// -/// let request = -/// request.new() -/// |> possum.get_plc_data(did) +/// let request = possum.get_plc_data(did) /// /// // You can use this decoder to extract the server endpoint /// let decoder = decode.at(["services", "atproto_pds", "endpoint"], decode.string) @@ -99,11 +96,8 @@ const com_atproto_sync = "xrpc/com.atproto.sync" /// ``` /// /// Documentation: [DID PLC Directory](https://web.plc.directory/) -pub fn get_plc_data( - request: request.Request(String), - did: did.Did, -) -> request.Request(String) { - request +pub fn get_plc_data(did: did.Did) -> request.Request(String) { + request.new() |> request.prepend_header("accept", "application/json") |> request.set_host("plc.directory") |> request.set_method(http.Get) @@ -116,14 +110,9 @@ pub fn get_plc_data( /// ## Examples /// /// ```gleam -/// import gleam/http/request -/// import possum/handle /// import possum /// -/// let assert Ok(handle) = handle.parse("gleam.run") -/// -/// request.new() -/// |> possum.resolve_well_known_did(handle) +/// let request = possum.resolve_well_known_did(host: "gleam.run") /// ``` /// /// ## Response @@ -133,11 +122,8 @@ pub fn get_plc_data( /// ``` /// /// Documentation: [HTTPS well-known Method](https://atproto.com/specs/handle#https-well-known-method) -pub fn resolve_well_known_did( - request: request.Request(String), - host: String, -) -> request.Request(String) { - request +pub fn resolve_well_known_did(host host: String) -> request.Request(String) { + request.new() |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(".well-known/atproto-did") @@ -157,11 +143,7 @@ pub fn resolve_well_known_did( /// import possum /// /// let assert Ok(handle) = handle.parse("gleam.run") -/// -/// let request = -/// request.new() -/// |> request.set_host("slingshot.microcosm.blue") -/// |> possum.resolve_handle(handle) +/// let request = possum.resolve_handle(handle, pds: "slingshot.microcosm.blue") /// ``` /// /// ## Response @@ -174,11 +156,12 @@ pub fn resolve_well_known_did( /// /// Endpoint Docs: [/xrpc/com.atproto.identity.resolveHandle](https://endpoints.bsky.app/#bluesky-app/tag/comatprotoidentity/GET/xrpc/com.atproto.identity.resolveHandle) pub fn resolve_handle( - request: request.Request(String), handle: handle.Handle, + pds host: String, ) -> request.Request(String) { - request + request.new() |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_identity <> ".resolveHandle") |> request.set_query([#("handle", handle.to_string(handle))]) @@ -205,10 +188,9 @@ pub fn resolve_handle( /// let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz") /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.create_session( +/// possum.create_session( /// did, +/// pds: "personal.data-server.pds", /// app_password: "bsky-app-password", /// allow_takendown: option.None, /// auth_factor_token: option.None @@ -234,8 +216,8 @@ pub fn resolve_handle( /// /// Endpoint Docs: [/xrpc/com.atproto.server.createSession](https://endpoints.bsky.app/#bluesky-app/tag/comatprotoserver/POST/xrpc/com.atproto.server.createSession) pub fn create_session( - request: request.Request(String), did: did.Did, + pds host: String, app_password app_password: String, allow_takendown allow_takendown: option.Option(Bool), auth_factor_token auth_factor_token: option.Option(String), @@ -255,10 +237,11 @@ pub fn create_session( option.None -> values } - request + request.new() |> request.prepend_header("accept", "application/json") |> request.prepend_header("content-type", "application/json") |> request.set_body(json.to_string(json.object(values))) + |> request.set_host(host) |> request.set_method(http.Post) |> request.set_path(com_atproto_server <> ".createSession") } @@ -269,13 +252,10 @@ pub fn create_session( /// ## Examples /// /// ```gleam -/// import gleam/http/request /// import possum /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.refresh_session("refresh-token") +/// possum.refresh_session("refresh-token", pds: "personal.data-server.pds") /// ``` /// /// ## Response @@ -297,12 +277,13 @@ pub fn create_session( /// /// Endpoint Docs: [/xrpc/com.atproto.server.refreshSession](https://endpoints.bsky.app/#bluesky-app/tag/comatprotoserver/POST/xrpc/com.atproto.server.refreshSession) pub fn refresh_session( - request: request.Request(String), - refresh token: String, + refresh_token token: String, + pds host: String, ) -> request.Request(String) { - request + request.new() |> authorized(token) |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Post) |> request.set_path(com_atproto_server <> ".refreshSession") } @@ -317,10 +298,8 @@ pub fn refresh_session( /// import possum /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") +/// possum.get_session_info(pds: "personal.data-server.pds") /// |> possum.authorized("access-token") -/// |> possum.get_session_info /// ``` /// /// ## Response @@ -339,11 +318,10 @@ pub fn refresh_session( /// ``` /// /// Endpoint Docs: [/xrpc/com.atproto.server.getSession](https://endpoints.bsky.app/#bluesky-app/tag/comatprotoserver/POST/xrpc/com.atproto.server.getSession) -pub fn get_session_info( - request: request.Request(String), -) -> request.Request(String) { - request +pub fn get_session_info(pds host: String) -> request.Request(String) { + request.new() |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_server <> ".getSession") } @@ -359,8 +337,7 @@ pub fn get_session_info( /// /// let request = /// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.authorized("access-token") +/// |> possum.authorized(access_token:"access-token") /// ``` /// pub fn authorized( @@ -380,11 +357,8 @@ pub fn authorized( /// import possum /// /// let assert Ok(did) = did.parse("did:plc:ewvi7nxzyoun6zhxrhs64oiz") -/// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.describe_repository(did) +/// possum.describe_repository(did, pds: "personal.data-server.pds") /// ``` /// /// ## Response @@ -403,11 +377,12 @@ pub fn authorized( /// /// Endpoint Docs: [/xrpc/com.atproto.repo.describeRepo](https://endpoints.bsky.app/#bluesky-app/tag/comatprotorepo/GET/xrpc/com.atproto.repo.describeRepo) pub fn describe_repository( - request: request.Request(String), did: did.Did, + pds host: String, ) -> request.Request(String) { - request + request.new() |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_repo <> ".describeRepo") |> request.set_query([#("repo", did.to_string(did))]) @@ -438,17 +413,16 @@ pub fn describe_repository( /// let assert Ok(collection) = nsid.parse("wibble.wobble.woo") /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.authorized("access-token") -/// |> possum.create_record( +/// possum.create_record( /// did, +/// pds: "personal.data-server.pds", /// collection:, /// rkey: "wibble", /// record: [], /// swap_commit: option.None, /// validate: option.None, /// ) +/// |> possum.authorized("access-token") /// ``` /// /// ## Response @@ -467,8 +441,8 @@ pub fn describe_repository( /// /// Endpoint Docs: [/xrpc/com.atproto.repo.createRecord](https://endpoints.bsky.app/#bluesky-app/tag/comatprotorepo/POST/xrpc/com.atproto.repo.createRecord) pub fn create_record( - request: request.Request(String), did: did.Did, + pds host: String, collection nsid: nsid.Nsid, rkey rkey: option.Option(String), record record: List(#(String, json.Json)), @@ -496,10 +470,11 @@ pub fn create_record( option.None -> body } - request + request.new() |> request.prepend_header("accept", "application/json") |> request.prepend_header("content-type", "application/json") |> request.set_body(json.to_string(json.object(body))) + |> request.set_host(host) |> request.set_method(http.Post) |> request.set_path(com_atproto_repo <> ".createRecord") } @@ -519,10 +494,9 @@ pub fn create_record( /// let assert Ok(collection) = nsid.parse("site.standard.document") /// /// let request = -/// request.new() -/// |> request.set_host("slingshot.microcosm.blue") -/// |> possum.get_record( +/// possum.get_record( /// did, +/// pds: "slingshot.microcosm.blue", /// collection:, /// rkey: "mn6n3lvibc2b", /// cursor: option.None, @@ -543,8 +517,8 @@ pub fn create_record( /// Endpoint Docs: [/xrpc/com.atproto.repo.getRecord](https://endpoints.bsky.app/#bluesky-app/tag/comatprotorepo/GET/xrpc/com.atproto.repo.getRecord) /// Documentation: [atproto.com](https://atproto.com/specs/record-key) pub fn get_record( - request: request.Request(String), did: did.Did, + pds host: String, collection nsid: nsid.Nsid, rkey rkey: String, cid cid: option.Option(String), @@ -560,8 +534,9 @@ pub fn get_record( option.None -> query } - request + request.new() |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_repo <> ".getRecord") |> request.set_query(query) @@ -581,10 +556,9 @@ pub fn get_record( /// let assert Ok(collection) = nsid.parse("site.standard.document") /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.list_records( +/// possum.list_records( /// did, +/// pds: "personal.data-server.pds", /// collection:, /// limit: option.Some(3), /// cursor: option.None, @@ -609,8 +583,8 @@ pub fn get_record( /// /// Endpoint Docs: [/xrpc/com.atproto.repo.listRecords](https://endpoints.bsky.app/#bluesky-app/tag/comatprotorepo/GET/xrpc/com.atproto.repo.listRecords) pub fn list_records( - request: request.Request(String), did: did.Did, + pds host: String, collection nsid: nsid.Nsid, limit limit: option.Option(Int), cursor cursor: option.Option(String), @@ -636,8 +610,9 @@ pub fn list_records( option.None -> query } - request + request.new() |> request.prepend_header("accept", "application/json") + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_repo <> ".listRecords") |> request.set_query(query) @@ -664,16 +639,15 @@ pub fn list_records( /// let assert Ok(collection) = nsid.parse("wibble.wobble.woo") /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.authorized("access-token") -/// |> possum.delete_record( +/// possum.delete_record( /// did, +/// pds: "personal.data-server.pds" /// collection:, /// rkey: "wibble-wobble", /// swap_commit: option.None, /// swap_record: option.None, /// ) +/// |> possum.authorized("access-token") /// ``` /// /// ## Response @@ -689,8 +663,8 @@ pub fn list_records( /// /// Endpoint Docs: [/xrpc/com.atproto.repo.deleteRecord](https://endpoints.bsky.app/#bluesky-app/tag/comatprotorepo/POST/xrpc/com.atproto.repo.deleteRecord) pub fn delete_record( - request: request.Request(String), did: did.Did, + pds host: String, collection nsid: nsid.Nsid, rkey rkey: String, swap_commit swap_commit: option.Option(String), @@ -712,10 +686,11 @@ pub fn delete_record( option.None -> body } - request + request.new() |> request.prepend_header("accept", "application/json") |> request.prepend_header("content-type", "application/json") |> request.set_body(json.to_string(json.object(body))) + |> request.set_host(host) |> request.set_method(http.Post) |> request.set_path(com_atproto_repo <> ".deleteRecord") } @@ -746,11 +721,9 @@ pub fn delete_record( /// let assert Ok(collection) = nsid.parse("target.collection.data") /// /// let request = -/// request.new() -/// |> request.set_host("personal.data-server.pds") -/// |> possum.authorized("access-token") -/// |> possum.put_record( +/// possum.put_record( /// did, +/// pds: "personal.data-server.pds", /// collection:, /// rkey: "wibble-wobble", /// record: [], @@ -758,6 +731,7 @@ pub fn delete_record( /// swap_record: option.None, /// validate: option.None, /// ) +/// |> possum.authorized("access-token") /// ``` /// /// ## Response @@ -778,6 +752,7 @@ pub fn delete_record( pub fn put_record( request: request.Request(String), did: did.Did, + pds host: String, collection nsid: nsid.Nsid, rkey rkey: String, record record: List(#(String, json.Json)), @@ -811,6 +786,7 @@ pub fn put_record( |> request.prepend_header("accept", "application/json") |> request.prepend_header("content-type", "application/json") |> request.set_body(json.to_string(json.object(body))) + |> request.set_host(host) |> request.set_method(http.Post) |> request.set_path(com_atproto_repo <> ".putRecord") } @@ -821,15 +797,16 @@ pub fn put_record( /// /// Endpoint Docs: [/xrpc/com.atproto.sync.getBlob](https://endpoints.bsky.app/#bluesky-app/tag/comatprotosync/GET/xrpc/com.atproto.sync.getBlob) pub fn get_blob( - request: request.Request(String), did: did.Did, cid: String, + pds host: String, ) -> request.Request(BitArray) { let query = [#("did", did.to_string(did)), #("cid", cid)] - request + request.new() |> request.prepend_header("accept", "*/*") |> request.set_body(<<>>) + |> request.set_host(host) |> request.set_method(http.Get) |> request.set_path(com_atproto_sync <> ".getBlob") |> request.set_query(query) diff --git a/test/possum_test.gleam b/test/possum_test.gleam index 8be48dd..c73f2d2 100644 --- a/test/possum_test.gleam +++ b/test/possum_test.gleam @@ -22,8 +22,6 @@ pub fn main() -> Nil { const slingshot = "slingshot.microcosm.blue" -const plc_directory = "plc.directory" - pub type Context { Context(handle: handle.Handle, did: did.Did, pds: String) } @@ -48,18 +46,14 @@ fn global_data() -> Context { let assert Ok(handle) = handle.parse("bsky.app") let assert Ok(did_response) = - request.new() - |> request.set_host(slingshot) - |> possum.resolve_handle(handle) + possum.resolve_handle(handle, pds: slingshot) |> httpc.send let assert Ok(did) = json.parse(did_response.body, decode.at(["did"], did.decoder())) let assert Ok(pds_response) = - request.new() - |> request.set_host(plc_directory) - |> possum.get_plc_data(did) + possum.get_plc_data(did) |> httpc.send let decoder = @@ -74,8 +68,7 @@ pub fn get_plc_data_test() -> Nil { let context = global_data() let assert Ok(response) = - request.new() - |> possum.get_plc_data(context.did) + possum.get_plc_data(context.did) |> httpc.send() let decoder = { @@ -95,9 +88,7 @@ pub fn resolve_handle_test() -> Nil { let context = global_data() let assert Ok(response) = - request.new() - |> request.set_host(slingshot) - |> possum.resolve_handle(context.handle) + possum.resolve_handle(context.handle, pds: slingshot) |> httpc.send let decoder = decode.at(["did"], decode.string) @@ -111,9 +102,7 @@ pub fn describe_repository_test() -> Nil { let context = global_data() let assert Ok(response) = - request.new() - |> request.set_host(context.pds) - |> possum.describe_repository(context.did) + possum.describe_repository(context.did, pds: context.pds) |> httpc.send let decoder = { @@ -143,10 +132,9 @@ pub fn get_record_test() -> Nil { let assert Ok(collection) = nsid.parse("app.bsky.actor.profile") let assert Ok(response) = - request.new() - |> request.set_host(slingshot) - |> possum.get_record( + possum.get_record( context.did, + pds: context.pds, collection:, rkey: "self", cid: option.None, @@ -169,10 +157,9 @@ pub fn get_blob_test() -> Nil { let assert Ok(bsky_profile) = nsid.parse("app.bsky.actor.profile") let assert Ok(bsky_query) = - request.new() - |> request.set_host(slingshot) - |> possum.get_record( + possum.get_record( context.did, + pds: slingshot, collection: bsky_profile, rkey: "self", cid: option.None, @@ -186,9 +173,7 @@ pub fn get_blob_test() -> Nil { ) let assert Ok(response) = - request.new() - |> request.set_host(context.pds) - |> possum.get_blob(context.did, rkey) + possum.get_blob(context.did, rkey, pds: context.pds) |> httpc.send_bits assert bit_array.byte_size(response.body) != 0 -- 2.51.2