import { WebContents } from 'electron' ; const getOwnerKey = ( webContents , contextId ) => { return `${ webContents . id }-${ contextId }` ; } ; class ObjectsRegistry { private nextId : number = 0 ; private storage : Record < number , { count : number ; object : any ; } > = { } ; private owners : Record < string , Map < number , number > > = { } ; private electronIds = new WeakMap < Object , number > ( ) ; add ( webContents , contextId , obj ) { const id = this . saveToStorage ( obj ) ; const ownerKey = getOwnerKey ( webContents , contextId ) ; let owner = this . owners [ ownerKey ] ; if ( ! owner ) { owner = this . owners [ ownerKey ] = new Map ( ) ; this . registerDeleteListener ( webContents , contextId ) ; } if ( ! owner . has ( id ) ) { owner . set ( id , 0 ) ; this . storage [ id ] . count ++ ; } owner . set ( id , owner . get ( id ) ! + 1 ) ; return id ; } get ( id ) { const pointer = this . storage [ id ] ; if ( pointer != null ) return pointer . object ; } remove ( webContents , contextId , id ) { const ownerKey = getOwnerKey ( webContents , contextId ) ; const owner = this . owners [ ownerKey ] ; if ( owner && owner . has ( id ) ) { const newRefCount = owner . get ( id ) ! - 1 ; if ( newRefCount <= 0 ) { owner . delete ( id ) ; this . dereference ( id ) ; } else { owner . set ( id , newRefCount ) ; } } } clear ( webContents , contextId ) { const ownerKey = getOwnerKey ( webContents , contextId ) ; const owner = this . owners [ ownerKey ] ; if ( ! owner ) return ; for ( const id of owner . keys ( ) ) this . dereference ( id ) ; delete this . owners [ ownerKey ] ; } private saveToStorage ( object ) { let id = this . electronIds . get ( object ) ; if ( ! id ) { id = ++ this . nextId ; this . storage [ id ] = { count : 0 , object : object } ; this . electronIds . set ( object , id ) ; } return id ; } private dereference ( id ) { const pointer = this . storage [ id ] ; if ( pointer == null ) { return ; } pointer . count -= 1 ; if ( pointer . count === 0 ) { this . electronIds . delete ( pointer . object ) ; delete this . storage [ id ] ; } } private registerDeleteListener ( webContents , contextId ) { const processHostId = contextId . split ( '-' ) [ 0 ] ; const listener = ( _ , deletedProcessHostId ) => { if ( deletedProcessHostId && deletedProcessHostId . toString ( ) === processHostId ) { webContents . removeListener ( 'render-view-deleted' as any , listener ) ; this . clear ( webContents , contextId ) ; } } ; webContents . on ( 'render-view-deleted' as any , listener ) ; } } export default new ObjectsRegistry ( ) ;