/**
 * Copyright 2018 Google Inc. All Rights Reserved.
 *
 * 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 Api from './api/v2' ; import { AppHandler , attach } from '../../assistant' ; import { ExceptionHandler , Argument , Intent , Traversed , ConversationAppOptions , ConversationApp , UnauthorizedError , } from './conversation' ; import { ActionsSdkConversation } from './conv' ; import { OAuth2Client } from 'google-auth-library' ; import * as common from '../../common' ; import { BuiltinFrameworkMetadata } from '../../framework' ; public export interface ActionsSdkIntentHandler < TConvData , TUserStorage , TConversation extends ActionsSdkConversation < TConvData , TUserStorage > , TArgument extends Argument > { public ( conv , /**
     * The user's raw input query.
     * See  Input * Same as `conv.input.raw`
      input , /**
     * The first argument value from the current intent.
     * See  Arguments * Same as `conv.arguments.parsed.list[0]`
      argument , /**
     * The first argument status from the current intent.
     * See  Arguments * Same as `conv.arguments.status.list[0]`
      status ) : Promise < any > | any ; } hidden export interface ActionSdkIntentHandlers { [ intent ] : ActionsSdkIntentHandler < { } , { } , ActionsSdkConversation < { } , { } > , Argument > | string | undefined ; } hidden export interface ActionsSdkHandlers < TConvData , TUserStorage , TConversation extends ActionsSdkConversation < TConvData , TUserStorage > > { intents : ActionSdkIntentHandlers ; catcher : ExceptionHandler < TUserStorage , TConversation > ; fallback ? : ActionsSdkIntentHandler < { } , { } , ActionsSdkConversation < { } , { } > , Argument > | string ; } public export interface ActionsSdkMiddleware < TConversationPlugin extends ActionsSdkConversation < { } , { } > > { public ( public conv , public framework ) : ( ActionsSdkConversation < { } , { } > & TConversationPlugin ) | void | Promise < ActionsSdkConversation < { } , { } > & TConversationPlugin > | Promise < void > ; } public export interface ActionsSdkApp < TConvData , TUserStorage , TConversation extends ActionsSdkConversation < TConvData , TUserStorage > > extends ConversationApp < TConvData , TUserStorage > { hidden _handlers : ActionsSdkHandlers < TConvData , TUserStorage , TConversation > ; param intent param handler public intent < TArgument extends Argument > ( intent , handler ) : this ; param intent param handler public intent < TArgument extends Argument > ( intent , handler ) : this ; public catch ( catcher ) : this ; public fallback ( handler ) : this ; hidden _middlewares : ActionsSdkMiddleware < ActionsSdkConversation < { } , { } > > [ ] ; public middleware < TConversationPlugin extends ActionsSdkConversation < { } , { } > > ( middleware ) : this ; public verification ? : ActionsSdkVerification | string ; } public export interface ActionsSdk { public < TConvData , TUserStorage , Conversation extends ActionsSdkConversation < TConvData , TUserStorage > = ActionsSdkConversation < TConvData , TUserStorage > > ( options ? ) : AppHandler & ActionsSdkApp < TConvData , TUserStorage , Conversation > ; public < Conversation extends ActionsSdkConversation < { } , { } > = ActionsSdkConversation < { } , { } > > ( options ? ) : AppHandler & ActionsSdkApp < { } , { } , Conversation > ; } public export interface ActionsSdkVerification { public project : string ; public status ? : number ; public error ? : string | ( ( error : string ) => string ) ; } public export interface ActionsSdkOptions < TConvData , TUserStorage > extends ConversationAppOptions < TConvData , TUserStorage > { example public verification ? : ActionsSdkVerification | string ; } example public export const actionssdk = < TConvData , TUserStorage , TConversation extends ActionsSdkConversation < TConvData , TUserStorage > > ( options = { } ) => attach < ActionsSdkApp < TConvData , TUserStorage , TConversation > > ( { _handlers : { intents : { } , catcher : ( conv , e ) => { throw e ; } , } , _middlewares : [ ] , intent < TInput > ( this , intents , handler ) { for ( const intent of common . toArray ( intents ) ) { this . _handlers . intents [ intent ] = handler ; } return this ; } , catch ( this , catcher ) { this . _handlers . catcher = catcher ; return this ; } , fallback ( this , handler ) { this . _handlers . fallback = handler ; return this ; } , middleware ( this , middleware ) { this . _middlewares . push ( middleware ) ; return this ; } , init : options . init , verification : options . verification , _client : options . verification || options . clientId ? new OAuth2Client ( options . clientId ) : undefined , auth : options . clientId ? { client : { id : options . clientId , } , } : undefined , ordersv3 : options . ordersv3 || false , async handler ( this , body , headers , metadata = { } ) { const { debug , init , verification , ordersv3 } = this ; if ( verification ) { const { project , status = 403 , error = ( e ) => e , } = typeof verification === 'string' ? { project : verification } : verification ; const token = headers [ 'authorization' ] 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 ActionsSdkConversation ( { body , headers , init : init && init ( ) , debug , ordersv3 , } ) ; if ( conv . user . profile . token ) { await conv . user . _verifyProfile ( this . _client ! , this . auth ! . client . id ) ; } for ( const middleware of this . _middlewares ) { const result = middleware ( conv , metadata ) ; conv = ( result instanceof ActionsSdkConversation ? result : ( await result ) || conv ) as ActionsSdkConversation < TConvData , TUserStorage > ; } const log = debug ? common . info : common . debug ; log ( 'Conversation' , common . stringify ( conv , 'request' , 'headers' , 'body' ) ) ; const { intent } = conv ; const traversed = { } ; let handler = intent ; while ( typeof handler !== 'function' ) { if ( typeof handler === 'undefined' ) { if ( ! this . _handlers . fallback ) { throw new Error ( `Actions SDK IntentHandler not found for intent: ${ intent }` ) ; } handler = this . _handlers . fallback ; continue ; } if ( traversed [ handler ] ) { throw new Error ( `Circular intent map detected: "${ handler }" traversed twice` ) ; } traversed [ handler ] = true ; handler = this . _handlers . intents [ handler ] ; } try { try { await handler ( conv , conv . input . raw , conv . arguments . parsed . list [ 0 ] , conv . arguments . status . list [ 0 ] ) ; } catch ( e ) { await this . _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 ) ;