Barazo AppView backend
barazo.forum
1// ---------------------------------------------------------------------------
2// OAuth scope constants for AT Protocol granular authorization.
3//
4// AT Protocol OAuth supports per-collection scope strings (e.g.,
5// `repo:forum.barazo.topic.post`) to limit access to specific record types.
6// Barazo requests only the minimum scopes needed for its functionality.
7//
8// Older PDS implementations may not support granular scopes. In that case,
9// the `transition:generic` fallback grants full repo access (same as legacy).
10// ---------------------------------------------------------------------------
11
12/** Base scopes for core Barazo forum operations (read/write own forum records). */
13export const BARAZO_BASE_SCOPES =
14 'atproto repo:forum.barazo.topic.post repo:forum.barazo.topic.reply repo:forum.barazo.interaction.reaction repo:forum.barazo.interaction.vote'
15
16/** Additional scopes needed for cross-posting to Bluesky and Frontpage. */
17export const CROSSPOST_ADDITIONAL_SCOPES =
18 'repo:app.bsky.feed.post?action=create repo:fyi.frontpage.post?action=create blob:image/*'
19
20/** Combined scopes for base + cross-posting. */
21export const BARAZO_CROSSPOST_SCOPES = `${BARAZO_BASE_SCOPES} ${CROSSPOST_ADDITIONAL_SCOPES}`
22
23/** Legacy fallback for PDS implementations that don't support granular scopes. */
24export const FALLBACK_SCOPE = 'atproto transition:generic'
25
26/**
27 * Check whether a granted scope string includes cross-post permissions.
28 * Returns true if the scope includes both Bluesky and Frontpage collections,
29 * or if it's the legacy `transition:generic` fallback (which grants everything).
30 */
31export function hasCrossPostScopes(scope: string): boolean {
32 if (isFallbackScope(scope)) {
33 return true
34 }
35 return scope.includes('repo:app.bsky.feed.post') && scope.includes('repo:fyi.frontpage.post')
36}
37
38/**
39 * Check whether a scope string is the legacy `transition:generic` fallback.
40 */
41export function isFallbackScope(scope: string): boolean {
42 return scope.includes('transition:generic')
43}