Auto-indexing service and GraphQL API for AT Protocol Records
at main 365 lines 7.9 kB view raw
1// Shared database type definitions 2 3import gleam/option.{type Option} 4 5/// A record stored in the database 6pub type Record { 7 Record( 8 uri: String, 9 cid: String, 10 did: String, 11 collection: String, 12 json: String, 13 indexed_at: String, 14 rkey: String, 15 ) 16} 17 18/// An actor (user) stored in the database 19pub type Actor { 20 Actor(did: String, handle: String, indexed_at: String) 21} 22 23/// A lexicon schema definition 24pub type Lexicon { 25 Lexicon(id: String, json: String, created_at: String) 26} 27 28/// Collection statistics 29pub type CollectionStat { 30 CollectionStat(collection: String, count: Int) 31} 32 33/// Result of inserting a record 34pub type InsertResult { 35 /// Record was newly inserted or updated 36 Inserted 37 /// Record was skipped (duplicate CID or unchanged) 38 Skipped 39} 40 41/// Date interval for date truncation in aggregations 42pub type DateInterval { 43 Hour 44 Day 45 Week 46 Month 47} 48 49/// A field to group by with optional date truncation 50pub type GroupByField { 51 SimpleField(field: String) 52 TruncatedField(field: String, interval: DateInterval) 53} 54 55/// A jetstream activity log entry 56pub type ActivityEntry { 57 ActivityEntry( 58 id: Int, 59 timestamp: String, 60 operation: String, 61 collection: String, 62 did: String, 63 status: String, 64 error_message: Option(String), 65 event_json: String, 66 ) 67} 68 69/// Activity bucket for aggregated data 70pub type ActivityBucket { 71 ActivityBucket( 72 timestamp: String, 73 create_count: Int, 74 update_count: Int, 75 delete_count: Int, 76 ) 77} 78 79// ===== OAuth Enum Types ===== 80 81/// OAuth 2.0 grant types 82pub type GrantType { 83 AuthorizationCode 84 RefreshToken 85 ClientCredentials 86 DeviceCode 87} 88 89/// OAuth 2.0 response types 90pub type ResponseType { 91 Code 92} 93 94/// Client authentication methods at token endpoint 95pub type ClientAuthMethod { 96 ClientSecretBasic 97 ClientSecretPost 98 PrivateKeyJwt 99 AuthNone 100} 101 102/// Client type classification 103pub type ClientType { 104 Public 105 Confidential 106} 107 108/// Token type 109pub type TokenType { 110 Bearer 111 DPoP 112} 113 114/// PKCE code challenge method 115pub type CodeChallengeMethod { 116 S256 117 Plain 118} 119 120// ===== OAuth Enum Conversion Functions ===== 121 122pub fn grant_type_to_string(gt: GrantType) -> String { 123 case gt { 124 AuthorizationCode -> "authorization_code" 125 RefreshToken -> "refresh_token" 126 ClientCredentials -> "client_credentials" 127 DeviceCode -> "urn:ietf:params:oauth:grant-type:device_code" 128 } 129} 130 131pub fn grant_type_from_string(s: String) -> Option(GrantType) { 132 case s { 133 "authorization_code" -> option.Some(AuthorizationCode) 134 "refresh_token" -> option.Some(RefreshToken) 135 "client_credentials" -> option.Some(ClientCredentials) 136 "urn:ietf:params:oauth:grant-type:device_code" -> option.Some(DeviceCode) 137 _ -> option.None 138 } 139} 140 141pub fn response_type_to_string(rt: ResponseType) -> String { 142 case rt { 143 Code -> "code" 144 } 145} 146 147pub fn response_type_from_string(s: String) -> Option(ResponseType) { 148 case s { 149 "code" -> option.Some(Code) 150 _ -> option.None 151 } 152} 153 154pub fn client_auth_method_to_string(method: ClientAuthMethod) -> String { 155 case method { 156 ClientSecretBasic -> "client_secret_basic" 157 ClientSecretPost -> "client_secret_post" 158 PrivateKeyJwt -> "private_key_jwt" 159 AuthNone -> "none" 160 } 161} 162 163pub fn client_auth_method_from_string(s: String) -> Option(ClientAuthMethod) { 164 case s { 165 "client_secret_basic" -> option.Some(ClientSecretBasic) 166 "client_secret_post" -> option.Some(ClientSecretPost) 167 "private_key_jwt" -> option.Some(PrivateKeyJwt) 168 "none" -> option.Some(AuthNone) 169 _ -> option.None 170 } 171} 172 173pub fn client_type_to_string(ct: ClientType) -> String { 174 case ct { 175 Public -> "public" 176 Confidential -> "confidential" 177 } 178} 179 180pub fn client_type_from_string(s: String) -> Option(ClientType) { 181 case s { 182 "public" -> option.Some(Public) 183 "confidential" -> option.Some(Confidential) 184 _ -> option.None 185 } 186} 187 188pub fn token_type_to_string(tt: TokenType) -> String { 189 case tt { 190 Bearer -> "Bearer" 191 DPoP -> "DPoP" 192 } 193} 194 195pub fn token_type_from_string(s: String) -> Option(TokenType) { 196 case s { 197 "Bearer" -> option.Some(Bearer) 198 "DPoP" -> option.Some(DPoP) 199 _ -> option.None 200 } 201} 202 203pub fn code_challenge_method_to_string(method: CodeChallengeMethod) -> String { 204 case method { 205 S256 -> "S256" 206 Plain -> "plain" 207 } 208} 209 210pub fn code_challenge_method_from_string( 211 s: String, 212) -> Option(CodeChallengeMethod) { 213 case s { 214 "S256" -> option.Some(S256) 215 "plain" -> option.Some(Plain) 216 _ -> option.None 217 } 218} 219 220// ===== OAuth Record Types ===== 221 222/// OAuth client registration 223pub type OAuthClient { 224 OAuthClient( 225 client_id: String, 226 client_secret: Option(String), 227 client_name: String, 228 redirect_uris: List(String), 229 grant_types: List(GrantType), 230 response_types: List(ResponseType), 231 scope: Option(String), 232 token_endpoint_auth_method: ClientAuthMethod, 233 client_type: ClientType, 234 created_at: Int, 235 updated_at: Int, 236 metadata: String, 237 access_token_expiration: Int, 238 refresh_token_expiration: Int, 239 require_redirect_exact: Bool, 240 registration_access_token: Option(String), 241 jwks: Option(String), 242 ) 243} 244 245/// OAuth access token 246pub type OAuthAccessToken { 247 OAuthAccessToken( 248 token: String, 249 token_type: TokenType, 250 client_id: String, 251 user_id: Option(String), 252 session_id: Option(String), 253 session_iteration: Option(Int), 254 scope: Option(String), 255 created_at: Int, 256 expires_at: Int, 257 revoked: Bool, 258 dpop_jkt: Option(String), 259 ) 260} 261 262/// OAuth refresh token 263pub type OAuthRefreshToken { 264 OAuthRefreshToken( 265 token: String, 266 access_token: String, 267 client_id: String, 268 user_id: String, 269 session_id: Option(String), 270 session_iteration: Option(Int), 271 scope: Option(String), 272 created_at: Int, 273 expires_at: Option(Int), 274 revoked: Bool, 275 ) 276} 277 278/// Pushed Authorization Request 279pub type OAuthParRequest { 280 OAuthParRequest( 281 request_uri: String, 282 authorization_request: String, 283 client_id: String, 284 created_at: Int, 285 expires_at: Int, 286 subject: Option(String), 287 metadata: String, 288 ) 289} 290 291/// DPoP nonce 292pub type OAuthDpopNonce { 293 OAuthDpopNonce(nonce: String, expires_at: Int) 294} 295 296/// Client authorization request during bridge flow 297pub type OAuthAuthRequest { 298 OAuthAuthRequest( 299 session_id: String, 300 client_id: String, 301 redirect_uri: String, 302 scope: Option(String), 303 state: Option(String), 304 code_challenge: Option(String), 305 code_challenge_method: Option(String), 306 response_type: String, 307 nonce: Option(String), 308 login_hint: Option(String), 309 created_at: Int, 310 expires_at: Int, 311 ) 312} 313 314/// ATP bridge session state 315pub type OAuthAtpSession { 316 OAuthAtpSession( 317 session_id: String, 318 iteration: Int, 319 did: Option(String), 320 session_created_at: Int, 321 atp_oauth_state: String, 322 signing_key_jkt: String, 323 dpop_key: String, 324 access_token: Option(String), 325 refresh_token: Option(String), 326 access_token_created_at: Option(Int), 327 access_token_expires_at: Option(Int), 328 access_token_scopes: Option(String), 329 session_exchanged_at: Option(Int), 330 exchange_error: Option(String), 331 ) 332} 333 334/// Outbound OAuth request to ATP 335pub type OAuthAtpRequest { 336 OAuthAtpRequest( 337 oauth_state: String, 338 authorization_server: String, 339 nonce: String, 340 pkce_verifier: String, 341 signing_public_key: String, 342 dpop_private_key: String, 343 created_at: Int, 344 expires_at: Int, 345 ) 346} 347 348/// OAuth authorization code 349pub type OAuthAuthorizationCode { 350 OAuthAuthorizationCode( 351 code: String, 352 client_id: String, 353 user_id: String, 354 session_id: Option(String), 355 session_iteration: Option(Int), 356 redirect_uri: String, 357 scope: Option(String), 358 code_challenge: Option(String), 359 code_challenge_method: Option(CodeChallengeMethod), 360 nonce: Option(String), 361 created_at: Int, 362 expires_at: Int, 363 used: Bool, 364 ) 365}