/**
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ import * as Schema from '../api/schema' ; import { AppHandler , attach } from '../assistant' ; import { ConversationV3 , ExceptionHandler , ConversationV3Options , ConversationVerification } from './conv' ; import * as common from '../common' ; import { BuiltinFrameworkMetadata } from '../framework' ; import { ServiceBaseApp } from '../assistant' ; import { AuthHeaderProcessor } from '../auth' ; import { setLogger , getLogger , debugLogger } from '../logger' ; import { OAuth2Client } from 'google-auth-library' ; example public export class UnauthorizedError extends Error { } public export interface ConversationV3Handler < TConversation extends ConversationV3 = ConversationV3 > { public ( conv ) : Promise < any > | any ; } hidden export interface ConversationV3Handlers { [ handler ] : ConversationV3Handler | undefined ; } hidden export interface ConversationV3AppHandlers < TConversation extends ConversationV3 > { handles : ConversationV3Handlers ; catcher : ExceptionHandler < TConversation > ; } public export interface ConversationV3Middleware < TConversationPlugin extends ConversationV3 > { public ( public conv , public framework ) : ( ConversationV3 & TConversationPlugin ) | void | Promise < ConversationV3 & TConversationPlugin > | Promise < void > ; } example public export interface ConversationV3App < TConversation extends ConversationV3 > extends ServiceBaseApp { param name param handler public handle ( name , handler ) : this ; public catch ( catcher ) : this ; public middleware < TConversationPlugin extends ConversationV3 > ( middleware ) : this ; hidden _internal : { handlers : ConversationV3AppHandlers < TConversation > ; middlewares : ConversationV3Middleware < ConversationV3 > [ ] ; } ; public verification ? : ConversationVerification | string ; hidden _client ? : OAuth2Client ; } public export interface Conversation { public < ConversationApp extends ConversationV3 = ConversationV3 > ( options ? ) : AppHandler & ConversationV3App < ConversationApp > ; } example public export const conversation = < TConversation extends ConversationV3 > ( options = { } ) => { if ( options . debug && ! options . logger ) { setLogger ( debugLogger ) ; } else { setLogger ( options . logger ) ; } const app = attach < ConversationV3App < TConversation > > ( { _internal : { handlers : { handles : { } , catcher : ( conv , e ) => { throw e ; } , } , middlewares : [ ] , } , handle ( this , names , handler ) { for ( const name of common . toArray ( names ) ) { this . _internal . handlers . handles [ name ] = handler ; } return this ; } , catch ( this , catcher ) { this . _internal . handlers . catcher = catcher ; return this ; } , middleware ( this , middleware ) { this . _internal . middlewares . push ( middleware ) ; return this ; } , verification : options . verification , _client : ( options . verification || options . clientId ) ? new OAuth2Client ( options . clientId ) : undefined , async handler ( this , body , headers , metadata = { } ) { const { clientId , verification } = this ; if ( verification ) { const { project , status = 403 , error = ( e ) => e , } = typeof verification === 'string' ? { project : verification } : verification ; const token = headers [ 'google-assistant-signature' ] as string ; try { await this . _client ! . verifyIdToken ( { idToken : token , audience : project , } ) ; } catch ( e ) { return { status , body : { error : typeof error === 'string' ? error : error ( `ID token verification failed: ${ e . stack || e . message || e }` ) , } , } ; } } let conv = new ConversationV3 ( { body , headers , } ) ; if ( headers . authorization && typeof headers . authorization === 'string' ) { const authHeaderProcessor = new AuthHeaderProcessor ( ) ; conv . user = await conv . user . processAuthHeader ( headers . authorization , authHeaderProcessor , clientId ) ; } for ( const middleware of this . _internal . middlewares ) { const result = middleware ( conv , metadata ) ; conv = ( result instanceof ConversationV3 ? result : ( ( await result ) || conv ) ) as ( ConversationV3 ) ; } getLogger ( ) . debug ( 'ConversationV3' , common . stringify ( conv , 'request' , 'headers' , 'body' ) ) ; const handlerName = conv . handler . name as string ; const handler = this . _internal . handlers . handles [ handlerName ] ; if ( typeof handler === 'undefined' ) { throw new Error ( `Handler not found for handle name: ${ handlerName }` ) ; } try { try { await handler ( conv ) ; } catch ( e ) { await this . _internal . handlers . catcher ( conv as TConversation , e ) ; } } catch ( e ) { if ( e instanceof UnauthorizedError ) { return { status : 401 , headers : { } , body : { } , } ; } throw e ; } return { status : 200 , headers : { } , body : conv . serialize ( ) , } ; } , } , options ) ; app . handle ( 'actions.handler.HEALTH_CHECK' , conv => { conv . json ( { } ) ; } ) ; return app ; } ;