import { createEvent , createStore , Scope } from 'effector' ; import { CancelledError , TimeoutError } from './error' ; import { Strategy } from './strategy' ; import { assign , read } from './tools' ; export type CancellablePromise < T > = Promise < T > & { cancel : ( strategy ? : Strategy | void ) => void ; } ; /**
 * Wrap promise to CancellablePromise, with `cancel` method
 */ export const cancellable = < Done > ( promise , abort ? , timeout ? ) : CancellablePromise < Done > => { let cancel ; const cancelable = new Promise < never > ( ( _ , reject ) => { let timeoutId ; const rejectWith = Cls => arg => { clearTimeout ( timeoutId ) ; reject ( new Cls ( arg ) ) ; abort && abort ( ) ; } ; cancel = rejectWith ( CancelledError ) ; if ( typeof timeout === 'number' ) { timeoutId = setTimeout ( rejectWith ( TimeoutError ) , timeout , timeout ) ; } } ) ; return assign ( Promise . race ( [ promise , cancelable ] ) , { cancel } ) ; } ; /**
 * Creates deferred promise
 */ export const defer = < Done > ( ) : { rs : ( value ? : Done | PromiseLike < Done > | undefined ) => void ; rj : ( reason ? : any ) => void ; req : Promise < Done > ; } => { const deferred = { } ; deferred . req = new Promise ( ( resolve , reject ) => { deferred . rs = resolve ; deferred . rj = reject ; } ) ; deferred . req . catch ( ( ) => { } ) ; return deferred ; } ; /**
 * Creates running promises storage
 * Store is automatically forked within the scope, which allows to use reeffect easily with fork api
 */ export const createRunning = < Done > ( ) => { const cancelAllEv = createEvent < Strategy | void > ( { sid : 'internal/cancelAll' , } ) ; const $running = createStore < CancellablePromise < Done > [ ] > ( [ ] , { sid : 'internal/$running' , serialize : 'ignore' , } ) ; $running . watch ( cancelAllEv , ( runs , strategy ) => runs . forEach ( p => p . cancel ( strategy ) ) ) ; const push = ( promise , scope ? ) => { read ( scope ) ( $running ) . push ( promise ) ; } ; const unpush = ( promise , scope ? ) => { if ( ! promise ) return ; read ( scope ) ( $running ) . splice ( read ( scope ) ( $running ) . indexOf ( promise ) , 1 ) ; } ; const cancelAll = ( strategy , scope ? ) => { read ( scope ) ( $running ) . forEach ( p => p . cancel ( strategy ) ) ; } ; return { $running , push , unpush , cancelAll , cancelAllEv } ; } ;