import deepEqual from 'fast-deep-equal' ; type PromiseCache < Response , Args extends any [ ] > = { promise : Promise < void > ; args : Args ; error ? : any ; response ? : Response ; } ; type PromiseFn < Response , Args extends any [ ] > = ( ... args : Args ) => Promise < Response > ; const globalCache = [ ] ; function handleAsset < Response , Args extends any [ ] > ( fn , cache , args , lifespan = 0 , preload = false ) { for ( const entry of cache ) { if ( deepEqual ( args , entry . args ) ) { if ( preload ) return ; if ( entry . error ) throw entry . error ; if ( entry . response ) return entry . response ; throw entry . promise ; } } const entry = { args , promise : fn ( ... args ) . then ( ( response ) => ( entry . response = ( response ?? true ) as Response ) ) . catch ( ( e ) => ( entry . error = e ?? 'unknown error' ) ) . then ( ( ) => { if ( lifespan > 0 ) { setTimeout ( ( ) => { const index = cache . indexOf ( entry ) ; if ( index !== - 1 ) cache . splice ( index , 1 ) ; } , lifespan ) ; } } ) , } ; cache . push ( entry ) ; if ( ! preload ) throw entry . promise ; } function clear < Response , Args extends any [ ] > ( cache , ... args ) { if ( args === undefined || args . length === 0 ) cache . splice ( 0 , cache . length ) ; else { const entry = cache . find ( ( entry ) => deepEqual ( args , entry . args ) ) ; if ( entry ) { const index = cache . indexOf ( entry ) ; if ( index !== - 1 ) cache . splice ( index , 1 ) ; } } } function createAsset < Response , Args extends any [ ] > ( fn , lifespan = 0 ) { const cache = [ ] ; return { throws throws read : ( ... args ) : Response => handleAsset ( fn , cache , args , lifespan ) as Response , preload : ( ... args ) : void => void handleAsset ( fn , cache , args , lifespan , true ) , clear : ( ... args ) => clear ( cache , ... args ) , peek : ( ... args ) : void | Response => cache . find ( ( entry ) => deepEqual ( args , entry . args ) ) ?. response , } ; } function useAsset < Response , Args extends any [ ] > ( fn , ... args ) { return handleAsset ( fn , globalCache as PromiseCache < Response , Args > [ ] , args , useAsset . lifespan ) as Response ; } useAsset . lifespan = 0 ; useAsset . clear = < Args extends any [ ] > ( ... args ) => clear ( globalCache , ... args ) ; useAsset . preload = < Response , Args extends any [ ] > ( fn , ... args ) => void handleAsset ( fn , globalCache as PromiseCache < Response , Args > [ ] , args , useAsset . lifespan , true ) ; useAsset . peek = < Response , Args extends any [ ] > ( ... args ) => globalCache . find ( ( entry ) => deepEqual ( args , entry . args ) ) ?. response as Response ; export { createAsset , useAsset } ;