import { App as OctokitApp } from "@octokit/app" ; import Octokit from "@octokit/rest" ; import Webhooks from "@octokit/webhooks" ; import { EventEmitter } from "promise-events" ; import { Cache } from "./cache" ; import { Context } from "./context" ; import { Logger } from "./logger" ; export type ApplicationFunction = ( app : Application ) => void ; export interface Options { logger : Logger ; app : OctokitApp ; cache : Cache ; Octokit : Octokit . Static ; catchErrors ? : boolean ; githubToken ? : string ; } export type OnCallback < T > = ( context : Context < T > ) => Promise < void > ; function isUnauthenticatedEvent ( event ) { return ( ! event . payload . installation || ( event . name === "installation" && event . payload . action === "deleted" ) ) ; } export type Dispatcher = ( event : Webhooks . WebhookEvent < any > ) => Promise < void > ; property export class Application { public events : EventEmitter ; public app : OctokitApp ; public cache : Cache ; public log : Logger ; public githubToken ? : string ; public Octokit : Octokit . Static ; private dispatcher ? : Dispatcher ; constructor ( options ? ) { const opts = options || ( { } as any ) ; this . events = new EventEmitter ( ) ; this . log = opts . logger ; this . app = opts . app ; this . cache = opts . cache ; this . githubToken = opts . githubToken ; this . Octokit = opts . Octokit ; } public withDispatcher ( d ) { this . dispatcher = d ; return this ; } param appFn public load ( appFn ) { if ( Array . isArray ( appFn ) ) { appFn . forEach ( a => this . load ( a ) ) ; } else { appFn ( this ) ; } return this ; } public async receive ( event ) { if ( this . dispatcher ) { return this . dispatcher ( event ) ; } await Promise . all ( [ this . events . emit ( "*" , event ) , this . events . emit ( event . name , event ) , this . events . emit ( `${ event . name }.${ event . payload . action }` , event ) , ] ) ; } param event param callback public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( event , callback ) ; public on ( eventName , callback ) ; public on ( eventName , callback ) { if ( typeof eventName === "string" ) { return this . events . on ( eventName , async ( event ) => { const log = this . log . child ( { component : "event" , id : event . id } ) ; try { const github = await this . authenticateEvent ( event , log ) ; const context = new Context ( event , github , log ) ; await callback ( context ) ; } catch ( err ) { if ( err . retryable ) { log . warn ( { err , event , retryable : true } ) ; } else { log . error ( { err , event , retryable : false } ) ; } throw err ; } } ) ; } else { eventName . forEach ( e => this . on ( e , callback ) ) ; } } param id returns private public async auth ( id ? , log = this . log ) { if ( process . env . GHE_HOST && /^https?:\/\// . test ( process . env . GHE_HOST ) ) { throw new Error ( "Your `GHE_HOST` environment variable should not begin with https:// or http://" ) ; } if ( id ) { return new this . Octokit ( { auth : async ( ) => { const accessToken = await this . app . getInstallationAccessToken ( { installationId : id , } ) ; return `token ${ accessToken }` ; } , baseUrl : process . env . GHE_HOST && `https://${ process . env . GHE_HOST }/api/v3` , logger : log . child ( { component : "github" , installation : String ( id ) } ) , } ) ; } const token = this . githubToken || this . app . getSignedJsonWebToken ( ) ; return new this . Octokit ( { auth : `Bearer ${ token }` , baseUrl : process . env . GHE_HOST && `https://${ process . env . GHE_HOST }/api/v3` , logger : log . child ( { component : "github" } ) , } ) ; } private authenticateEvent ( event , log ) { if ( this . githubToken ) { return this . auth ( ) ; } if ( isUnauthenticatedEvent ( event ) ) { log . debug ( "`context.github` is unauthenticated. See https://probot.github.io/docs/github-api/#unauthenticated-events" ) ; return this . auth ( ) ; } return this . auth ( event . payload . installation . id , log ) ; } }