forked from
slices.network/quickslice
Auto-indexing service and GraphQL API for AT Protocol Records
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}