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