@@ -10,6 +10,44 @@ export const Method = z
1010 . object ( {
1111 type : z . union ( [ z . literal ( "oauth" ) , z . literal ( "api" ) ] ) ,
1212 label : z . string ( ) ,
13+ prompts : z
14+ . array (
15+ z . union ( [
16+ z . object ( {
17+ type : z . literal ( "text" ) ,
18+ key : z . string ( ) ,
19+ message : z . string ( ) ,
20+ placeholder : z . string ( ) . optional ( ) ,
21+ when : z
22+ . object ( {
23+ key : z . string ( ) ,
24+ op : z . union ( [ z . literal ( "eq" ) , z . literal ( "neq" ) ] ) ,
25+ value : z . string ( ) ,
26+ } )
27+ . optional ( ) ,
28+ } ) ,
29+ z . object ( {
30+ type : z . literal ( "select" ) ,
31+ key : z . string ( ) ,
32+ message : z . string ( ) ,
33+ options : z . array (
34+ z . object ( {
35+ label : z . string ( ) ,
36+ value : z . string ( ) ,
37+ hint : z . string ( ) . optional ( ) ,
38+ } ) ,
39+ ) ,
40+ when : z
41+ . object ( {
42+ key : z . string ( ) ,
43+ op : z . union ( [ z . literal ( "eq" ) , z . literal ( "neq" ) ] ) ,
44+ value : z . string ( ) ,
45+ } )
46+ . optional ( ) ,
47+ } ) ,
48+ ] ) ,
49+ )
50+ . optional ( ) ,
1351 } )
1452 . meta ( {
1553 ref : "ProviderAuthMethod" ,
@@ -43,16 +81,29 @@ export const OauthCodeMissing = NamedError.create(
4381
4482export const OauthCallbackFailed = NamedError . create ( "ProviderAuthOauthCallbackFailed" , z . object ( { } ) )
4583
84+ export const ValidationFailed = NamedError . create (
85+ "ProviderAuthValidationFailed" ,
86+ z . object ( {
87+ field : z . string ( ) ,
88+ message : z . string ( ) ,
89+ } ) ,
90+ )
91+
4692export type ProviderAuthError =
4793 | Auth . AuthServiceError
4894 | InstanceType < typeof OauthMissing >
4995 | InstanceType < typeof OauthCodeMissing >
5096 | InstanceType < typeof OauthCallbackFailed >
97+ | InstanceType < typeof ValidationFailed >
5198
5299export namespace ProviderAuthService {
53100 export interface Service {
54101 readonly methods : ( ) => Effect . Effect < Record < string , Method [ ] > >
55- readonly authorize : ( input : { providerID : ProviderID ; method : number } ) => Effect . Effect < Authorization | undefined >
102+ readonly authorize : ( input : {
103+ providerID : ProviderID
104+ method : number
105+ inputs ?: Record < string , string >
106+ } ) => Effect . Effect < Authorization | undefined , ProviderAuthError >
56107 readonly callback : ( input : {
57108 providerID : ProviderID
58109 method : number
@@ -80,16 +131,52 @@ export class ProviderAuthService extends ServiceMap.Service<ProviderAuthService,
80131 const pending = new Map < ProviderID , AuthOuathResult > ( )
81132
82133 const methods = Effect . fn ( "ProviderAuthService.methods" ) ( function * ( ) {
83- return Record . map ( hooks , ( item ) => item . methods . map ( ( method ) : Method => Struct . pick ( method , [ "type" , "label" ] ) ) )
134+ return Record . map ( hooks , ( item ) =>
135+ item . methods . map (
136+ ( method ) : Method => ( {
137+ type : method . type ,
138+ label : method . label ,
139+ prompts : method . prompts ?. map ( ( prompt ) => {
140+ if ( prompt . type === "select" ) {
141+ return {
142+ type : "select" as const ,
143+ key : prompt . key ,
144+ message : prompt . message ,
145+ options : prompt . options ,
146+ when : prompt . when ,
147+ }
148+ }
149+ return {
150+ type : "text" as const ,
151+ key : prompt . key ,
152+ message : prompt . message ,
153+ placeholder : prompt . placeholder ,
154+ when : prompt . when ,
155+ }
156+ } ) ,
157+ } ) ,
158+ ) ,
159+ )
84160 } )
85161
86162 const authorize = Effect . fn ( "ProviderAuthService.authorize" ) ( function * ( input : {
87163 providerID : ProviderID
88164 method : number
165+ inputs ?: Record < string , string >
89166 } ) {
90167 const method = hooks [ input . providerID ] . methods [ input . method ]
91168 if ( method . type !== "oauth" ) return
92- const result = yield * Effect . promise ( ( ) => method . authorize ( ) )
169+
170+ if ( method . prompts && input . inputs ) {
171+ for ( const prompt of method . prompts ) {
172+ if ( prompt . type === "text" && prompt . validate && input . inputs [ prompt . key ] !== undefined ) {
173+ const error = prompt . validate ( input . inputs [ prompt . key ] )
174+ if ( error ) return yield * Effect . fail ( new ValidationFailed ( { field : prompt . key , message : error } ) )
175+ }
176+ }
177+ }
178+
179+ const result = yield * Effect . promise ( ( ) => method . authorize ( input . inputs ) )
93180 pending . set ( input . providerID , result )
94181 return {
95182 url : result . url ,
0 commit comments