import AbstractStore from "../store" ; /** An in-memory store implementation. */ export default class MemoryStore extends AbstractStore { private data : { [ key ] : { ex : number ; data : any ; } ; } ; private interval ? : NodeJS . Timeout ; constructor ( ) { super ( ) ; this . data = Object . create ( null ) ; this . interval = setInterval ( ( ) => this . gc ( ) , 60 * 1000 ) ; } /** Fetch JSON from cache or using HTTP GET. */ async fetchCached ( cacheId , url ) { this . gc ( ) ; const key = `cache:${ cacheId }` ; const item = this . data [ key ] ; if ( item ) { return item . data ; } const { ttl , data } = await this . fetch ( url ) ; this . data [ key ] = { ex : Date . now ( ) + ttl , data } ; return data ; } /** Generate and store a nonce. */ async createNonce ( email ) { const nonce = this . generateNonce ( email ) ; const key = `nonce:${ nonce }` ; this . data [ key ] = { ex : Date . now ( ) + this . nonceTtl , data : email } ; return nonce ; } /** Consume a nonce, and check if it's valid for the given email address. */ async consumeNonce ( nonce , email ) { this . gc ( ) ; const key = `nonce:${ nonce }` ; const item = this . data [ key ] ; delete this . data [ key ] ; if ( ! item || item . data !== email ) { throw Error ( "Invalid or expired nonce" ) ; } } /** Destroy the store. */ destroy ( ) { if ( this . interval !== undefined ) { clearInterval ( this . interval ) ; this . interval = undefined ; } } /** Remove expired items from the store */ private gc ( ) { const now = Date . now ( ) ; for ( const key of Object . keys ( this . data ) ) { if ( this . data [ key ] . ex <= now ) { delete this . data [ key ] ; } } } }