this repo has no description
1use std::collections::HashMap; 2use std::sync::LazyLock; 3 4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 5pub enum ScopeCategory { 6 Core, 7 Transition, 8 Repo, 9 Blob, 10 Rpc, 11 Account, 12} 13 14impl ScopeCategory { 15 pub fn display_name(&self) -> &'static str { 16 match self { 17 ScopeCategory::Core => "Core Access", 18 ScopeCategory::Transition => "Transition", 19 ScopeCategory::Repo => "Repository", 20 ScopeCategory::Blob => "Media", 21 ScopeCategory::Rpc => "API Access", 22 ScopeCategory::Account => "Account", 23 } 24 } 25} 26 27#[derive(Debug, Clone)] 28pub struct ScopeDefinition { 29 pub scope: &'static str, 30 pub category: ScopeCategory, 31 pub required: bool, 32 pub description: &'static str, 33 pub display_name: &'static str, 34} 35 36pub static SCOPE_DEFINITIONS: LazyLock<HashMap<&'static str, ScopeDefinition>> = 37 LazyLock::new(|| { 38 let definitions = vec![ 39 ScopeDefinition { 40 scope: "atproto", 41 category: ScopeCategory::Core, 42 required: true, 43 description: "Full access to read, write, and manage this account", 44 display_name: "Full Account Access", 45 }, 46 ScopeDefinition { 47 scope: "transition:generic", 48 category: ScopeCategory::Transition, 49 required: false, 50 description: "Generic transition scope for compatibility", 51 display_name: "Transition Access", 52 }, 53 ScopeDefinition { 54 scope: "transition:chat.bsky", 55 category: ScopeCategory::Transition, 56 required: false, 57 description: "Access to Bluesky chat features", 58 display_name: "Chat Access", 59 }, 60 ScopeDefinition { 61 scope: "transition:email", 62 category: ScopeCategory::Account, 63 required: false, 64 description: "Read your account email address", 65 display_name: "Email Access", 66 }, 67 ScopeDefinition { 68 scope: "repo:*?action=create", 69 category: ScopeCategory::Repo, 70 required: false, 71 description: "Create new records in your repository", 72 display_name: "Create Records", 73 }, 74 ScopeDefinition { 75 scope: "repo:*?action=update", 76 category: ScopeCategory::Repo, 77 required: false, 78 description: "Update existing records in your repository", 79 display_name: "Update Records", 80 }, 81 ScopeDefinition { 82 scope: "repo:*?action=delete", 83 category: ScopeCategory::Repo, 84 required: false, 85 description: "Delete records from your repository", 86 display_name: "Delete Records", 87 }, 88 ScopeDefinition { 89 scope: "blob:*/*", 90 category: ScopeCategory::Blob, 91 required: false, 92 description: "Upload images, videos, and other media files", 93 display_name: "Upload Media", 94 }, 95 ScopeDefinition { 96 scope: "repo:*", 97 category: ScopeCategory::Repo, 98 required: false, 99 description: "Full read and write access to all repository records", 100 display_name: "Full Repository Access", 101 }, 102 ScopeDefinition { 103 scope: "account:*?action=manage", 104 category: ScopeCategory::Account, 105 required: false, 106 description: "Manage account settings and preferences", 107 display_name: "Manage Account", 108 }, 109 ]; 110 111 definitions.into_iter().map(|d| (d.scope, d)).collect() 112 }); 113 114#[allow(dead_code)] 115pub fn get_scope_definition(scope: &str) -> Option<&'static ScopeDefinition> { 116 SCOPE_DEFINITIONS.get(scope) 117} 118 119#[allow(dead_code)] 120pub fn is_valid_scope(scope: &str) -> bool { 121 if SCOPE_DEFINITIONS.contains_key(scope) { 122 return true; 123 } 124 if scope.starts_with("ref:") { 125 return true; 126 } 127 false 128} 129 130#[allow(dead_code)] 131pub fn get_required_scopes() -> Vec<&'static str> { 132 SCOPE_DEFINITIONS 133 .values() 134 .filter(|d| d.required) 135 .map(|d| d.scope) 136 .collect() 137} 138 139#[allow(dead_code)] 140pub fn format_scope_for_display(scope: &str) -> String { 141 if let Some(def) = get_scope_definition(scope) { 142 def.description.to_string() 143 } else if scope.starts_with("ref:") { 144 "Referenced scope".to_string() 145 } else { 146 format!("Access to {}", scope) 147 } 148}