import { IModulePatcher , IModulePatchMap , makePatchingRequire } from "./patchRequire" ; export { PatchFunction , IModulePatcher , makePatchingRequire } from "./patchRequire" ; export interface ISpanContext { traceId : string ; spanId : string ; traceFlags ? : string ; tracestate ? : string ; } type ScopeManager = any ; export interface IStandardEvent < T > { timestamp : number ; data : T ; } export type ISubscriber < T > = ( event : IStandardEvent < T > ) => void ; export type IFilter = ( publishing : boolean ) => boolean ; interface IFilteredSubscriber < T > { listener : ISubscriber < T > ; filter : IFilter ; } export interface IChannel { shouldPublish ( name ) : boolean ; publish < T > ( name , event ) : void ; subscribe < T > ( name , listener , filter ? ) : void ; unsubscribe < T > ( name , listener , filter ? ) : void ; bindToContext < T extends Function > ( cb ) : T ; addContextPreservation < T extends Function > ( preserver ) : void ; registerMonkeyPatch ( packageName , patcher ) : void ; spanContextPropagator : ScopeManager ; } const trueFilter = ( publishing ) => true ; class ContextPreservingEventEmitter implements IChannel { public version : string = require ( "./../../package.json" ) . version ; public spanContextPropagator : ScopeManager ; private subscribers : { [ key ] : Array < IFilteredSubscriber < any > > ; } = { } ; private contextPreservationFunction : < F extends Function > ( cb : F ) => F = ( cb ) => cb ; private knownPatches : IModulePatchMap = { } ; private currentlyPublishing : boolean = false ; public shouldPublish ( name ) { const listeners = this . subscribers [ name ] ; if ( listeners ) { return listeners . some ( ( { filter } ) => ! filter || filter ( false ) ) ; } return false ; } public publish < T > ( name , event ) { if ( this . currentlyPublishing ) { return ; } const listeners = this . subscribers [ name ] ; if ( listeners ) { const standardEvent = { timestamp : Date . now ( ) , data : event , } ; this . currentlyPublishing = true ; listeners . forEach ( ( { listener , filter } ) => { try { if ( filter && filter ( true ) ) { listener ( standardEvent ) ; } } catch ( e ) { } } ) ; this . currentlyPublishing = false ; } } public subscribe < T > ( name , listener , filter = trueFilter ) { if ( ! this . subscribers [ name ] ) { this . subscribers [ name ] = [ ] ; } this . subscribers [ name ] . push ( { listener , filter } ) ; } public unsubscribe < T > ( name , listener , filter = trueFilter ) { const listeners = this . subscribers [ name ] ; if ( listeners ) { for ( let index = 0 ; index < listeners . length ; ++ index ) { if ( listeners [ index ] . listener === listener && listeners [ index ] . filter === filter ) { listeners . splice ( index , 1 ) ; return true ; } } } return false ; } public reset ( ) { this . subscribers = { } ; this . contextPreservationFunction = ( cb ) => cb ; Object . getOwnPropertyNames ( this . knownPatches ) . forEach ( ( prop ) => delete this . knownPatches [ prop ] ) ; } public bindToContext < T extends Function > ( cb ) { return this . contextPreservationFunction ( cb ) ; } public addContextPreservation < T extends Function > ( preserver ) { const previousPreservationStack = this . contextPreservationFunction ; this . contextPreservationFunction = ( ( cb ) => preserver ( previousPreservationStack ( cb ) ) ) as any ; } public registerMonkeyPatch ( packageName , patcher ) { if ( ! this . knownPatches [ packageName ] ) { this . knownPatches [ packageName ] = [ ] ; } this . knownPatches [ packageName ] . push ( patcher ) ; } public getPatchesObject ( ) { return this . knownPatches ; } } declare const global ; if ( ! global . diagnosticsSource ) { global . diagnosticsSource = new ContextPreservingEventEmitter ( ) ; const moduleModule = require ( "module" ) ; moduleModule . prototype . require = makePatchingRequire ( global . diagnosticsSource . getPatchesObject ( ) ) ; } export const channel = global . diagnosticsSource ;