@@ -18,7 +18,7 @@ import { z } from "zod";
1818 *
1919 * @constant
2020 */
21- export const ATPROTO_SCOPE = ' atproto' as const ;
21+ export const ATPROTO_SCOPE = " atproto" as const ;
2222
2323/**
2424 * Transitional OAuth scopes for legacy compatibility.
@@ -31,11 +31,11 @@ export const ATPROTO_SCOPE = 'atproto' as const;
3131 */
3232export const TRANSITION_SCOPES = {
3333 /** Broad PDS permissions including record creation, blob uploads, and preferences */
34- GENERIC : ' transition:generic' ,
34+ GENERIC : " transition:generic" ,
3535 /** Direct messages access (requires transition:generic) */
36- CHAT : ' transition:chat.bsky' ,
36+ CHAT : " transition:chat.bsky" ,
3737 /** Email address and confirmation status */
38- EMAIL : ' transition:email' ,
38+ EMAIL : " transition:email" ,
3939} as const ;
4040
4141/**
@@ -49,11 +49,9 @@ export const TRANSITION_SCOPES = {
4949 * TransitionScopeSchema.parse('invalid'); // Throws ZodError
5050 * ```
5151 */
52- export const TransitionScopeSchema = z . enum ( [
53- 'transition:generic' ,
54- 'transition:chat.bsky' ,
55- 'transition:email' ,
56- ] ) . describe ( 'Legacy transitional OAuth scopes' ) ;
52+ export const TransitionScopeSchema = z
53+ . enum ( [ "transition:generic" , "transition:chat.bsky" , "transition:email" ] )
54+ . describe ( "Legacy transitional OAuth scopes" ) ;
5755
5856/**
5957 * Type for transitional scopes inferred from schema.
@@ -65,7 +63,7 @@ export type TransitionScope = z.infer<typeof TransitionScopeSchema>;
6563 *
6664 * Account attributes specify what aspect of the account is being accessed.
6765 */
68- export const AccountAttrSchema = z . enum ( [ ' email' , ' repo' ] ) ;
66+ export const AccountAttrSchema = z . enum ( [ " email" , " repo" ] ) ;
6967
7068/**
7169 * Type for account attributes inferred from schema.
@@ -77,7 +75,7 @@ export type AccountAttr = z.infer<typeof AccountAttrSchema>;
7775 *
7876 * Account actions specify the level of access (read-only or management).
7977 */
80- export const AccountActionSchema = z . enum ( [ ' read' , ' manage' ] ) ;
78+ export const AccountActionSchema = z . enum ( [ " read" , " manage" ] ) ;
8179
8280/**
8381 * Type for account actions inferred from schema.
@@ -89,7 +87,7 @@ export type AccountAction = z.infer<typeof AccountActionSchema>;
8987 *
9088 * Repository actions specify what operations can be performed on records.
9189 */
92- export const RepoActionSchema = z . enum ( [ ' create' , ' update' , ' delete' ] ) ;
90+ export const RepoActionSchema = z . enum ( [ " create" , " update" , " delete" ] ) ;
9391
9492/**
9593 * Type for repository actions inferred from schema.
@@ -101,7 +99,7 @@ export type RepoAction = z.infer<typeof RepoActionSchema>;
10199 *
102100 * Identity attributes specify what identity information can be managed.
103101 */
104- export const IdentityAttrSchema = z . enum ( [ ' handle' , '*' ] ) ;
102+ export const IdentityAttrSchema = z . enum ( [ " handle" , "*" ] ) ;
105103
106104/**
107105 * Type for identity attributes inferred from schema.
@@ -120,10 +118,12 @@ export type IdentityAttr = z.infer<typeof IdentityAttrSchema>;
120118 * MimeTypeSchema.parse('invalid'); // Throws ZodError
121119 * ```
122120 */
123- export const MimeTypeSchema = z . string ( ) . regex (
124- / ^ [ a - z ] + \/ [ a - z 0 - 9 * + - ] + $ / i,
125- 'Invalid MIME type pattern. Expected format: type/subtype (e.g., "image/*" or "video/mp4")'
126- ) ;
121+ export const MimeTypeSchema = z
122+ . string ( )
123+ . regex (
124+ / ^ [ a - z ] + \/ [ a - z 0 - 9 * + - ] + $ / i,
125+ 'Invalid MIME type pattern. Expected format: type/subtype (e.g., "image/*" or "video/mp4")' ,
126+ ) ;
127127
128128/**
129129 * Zod schema for NSID (Namespaced Identifier).
@@ -140,7 +140,46 @@ export const MimeTypeSchema = z.string().regex(
140140 * NsidSchema.parse('InvalidNSID'); // Throws ZodError
141141 * ```
142142 */
143- export const NsidSchema = z . string ( ) . regex (
144- / ^ [ a - z ] [ a - z 0 - 9 - ] * ( \. [ a - z ] [ a - z 0 - 9 - ] * ) + $ / ,
145- 'Invalid NSID format. Expected reverse-DNS format (e.g., "app.bsky.feed.post")'
146- ) ;
143+ export const NsidSchema = z
144+ . string ( )
145+ . regex (
146+ / ^ [ a - z ] [ a - z 0 - 9 - ] * ( \. [ a - z ] [ a - z 0 - 9 - ] * ) + $ / ,
147+ 'Invalid NSID format. Expected reverse-DNS format (e.g., "app.bsky.feed.post")' ,
148+ ) ;
149+
150+ /**
151+ * Zod schema for account permission.
152+ *
153+ * Account permissions control access to account-level information like email
154+ * and repository management.
155+ *
156+ * @example Without action (read-only)
157+ * ```typescript
158+ * const input = { type: 'account', attr: 'email' };
159+ * AccountPermissionSchema.parse(input); // Returns: "account:email"
160+ * ```
161+ *
162+ * @example With action
163+ * ```typescript
164+ * const input = { type: 'account', attr: 'email', action: 'manage' };
165+ * AccountPermissionSchema.parse(input); // Returns: "account:email?action=manage"
166+ * ```
167+ */
168+ export const AccountPermissionSchema = z
169+ . object ( {
170+ type : z . literal ( "account" ) ,
171+ attr : AccountAttrSchema ,
172+ action : AccountActionSchema . optional ( ) ,
173+ } )
174+ . transform ( ( { attr, action } ) => {
175+ let perm = `account:${ attr } ` ;
176+ if ( action ) {
177+ perm += `?action=${ action } ` ;
178+ }
179+ return perm ;
180+ } ) ;
181+
182+ /**
183+ * Input type for account permission (before transform).
184+ */
185+ export type AccountPermissionInput = z . input < typeof AccountPermissionSchema > ;
0 commit comments