import { StateMachine , Event , EventObject , CancelAction , DefaultContext , ActionObject , StateSchema , ActivityActionObject , SpecialTargets , ActionTypes , InvokeDefinition , SendActionObject , ServiceConfig , InvokeCallback , DisposeActivityFunction , StateValue , InterpreterOptions , ActivityDefinition , SingleOrArray , Subscribable , DoneEvent , MachineOptions , ActionFunctionMap , SCXML , EventData , Observer , Spawnable , Typestate , AnyEventObject , AnyInterpreter , ActorRef , ActorRefFrom , Behavior , StopActionObject , Subscription } from './types' ; import { State , bindActionToState , isState } from './State' ; import * as actionTypes from './actionTypes' ; import { doneInvoke , error , getActionFunction , initEvent } from './actions' ; import { IS_PRODUCTION } from './environment' ; import { isPromiseLike , mapContext , warn , keys , isArray , isFunction , isString , isObservable , uniqueId , isMachine , toEventObject , toSCXMLEvent , reportUnhandledExceptionOnInvocation , symbolObservable , toInvokeSource , toObserver , isActor , isBehavior , interopSymbols } from './utils' ; import { Scheduler } from './scheduler' ; import { Actor , isSpawnedActor , createDeferredActor } from './Actor' ; import { isInFinalState } from './stateUtils' ; import { registry } from './registry' ; import { getGlobal , registerService } from './devTools' ; import * as serviceScope from './serviceScope' ; import { spawnBehavior } from './behaviors' ; export type StateListener < TContext , TEvent extends EventObject , TStateSchema extends StateSchema < TContext > = any , TTypestate extends Typestate < TContext > = { value : any ; context : TContext ; } > = ( state : State < TContext , TEvent , TStateSchema , TTypestate > , event : TEvent ) => void ; export type ContextListener < TContext = DefaultContext > = ( context : TContext , prevContext : TContext | undefined ) => void ; export type EventListener < TEvent extends EventObject = EventObject > = ( event : TEvent ) => void ; export type Listener = ( ) => void ; export interface Clock { setTimeout ( fn , timeout ) : any ; clearTimeout ( id ) : void ; } interface SpawnOptions { name ? : string ; autoForward ? : boolean ; sync ? : boolean ; } const DEFAULT_SPAWN_OPTIONS = { sync : false , autoForward : false } ; export enum InterpreterStatus { NotStarted , Running , Stopped } export class Interpreter < TContext , TStateSchema extends StateSchema = any , TEvent extends EventObject = EventObject , TTypestate extends Typestate < TContext > = { value : any ; context : TContext ; } > implements ActorRef < TEvent , State < TContext , TEvent , TStateSchema , TTypestate > > { /**
     * The default interpreter options:
     *
     * - `clock` uses the global `setTimeout` and `clearTimeout` functions
     * - `logger` uses the global `console.log()` method
     */ public static defaultOptions : InterpreterOptions = ( ( global ) => ( { execute : true , deferEvents : true , clock : { setTimeout : ( fn , ms ) => { return setTimeout ( fn , ms ) ; } , clearTimeout : ( id ) => { return clearTimeout ( id ) ; } } , logger : global . console . log . bind ( console ) , devTools : false } ) ) ( typeof self !== 'undefined' ? self : global ) ; /**
     * The current state of the interpreted machine.
     */ private _state ? : State < TContext , TEvent , TStateSchema , TTypestate > ; private _initialState ? : State < TContext , TEvent , TStateSchema , TTypestate > ; /**
     * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
     */ public clock : Clock ; public options : Readonly < InterpreterOptions > ; private scheduler : Scheduler = new Scheduler ( ) ; private delayedEventsMap : Record < string , number > = { } ; private listeners : Set < StateListener < TContext , TEvent , TStateSchema , TTypestate > > = new Set ( ) ; private contextListeners : Set < ContextListener < TContext > > = new Set ( ) ; private stopListeners : Set < Listener > = new Set ( ) ; private doneListeners : Set < EventListener > = new Set ( ) ; private eventListeners : Set < EventListener > = new Set ( ) ; private sendListeners : Set < EventListener > = new Set ( ) ; private logger : ( ... args : any [ ] ) => void ; /**
     * Whether the service is started.
     */ public initialized = false ; public status : InterpreterStatus = InterpreterStatus . NotStarted ; public parent ? : Interpreter < any > ; public id : string ; /**
     * The globally unique process ID for this invocation.
     */ public sessionId : string ; public children : Map < string | number , ActorRef < any > > = new Map ( ) ; private forwardTo : Set < string > = new Set ( ) ; private devTools ? : any ; param machine param options constructor ( public machine , options = Interpreter . defaultOptions ) { const resolvedOptions = { ... Interpreter . defaultOptions , ... options } ; const { clock , logger , parent , id } = resolvedOptions ; const resolvedId = id !== undefined ? id : machine . id ; this . id = resolvedId ; this . logger = logger ; this . clock = clock ; this . parent = parent ; this . options = resolvedOptions ; this . scheduler = new Scheduler ( { deferEvents : this . options . deferEvents } ) ; this . sessionId = registry . bookId ( ) ; } public get initialState ( ) : State < TContext , TEvent , TStateSchema , TTypestate > { if ( this . _initialState ) { return this . _initialState ; } return serviceScope . provide ( this , ( ) => { this . _initialState = this . machine . initialState ; return this . _initialState ; } ) ; } public get state ( ) : State < TContext , TEvent , TStateSchema , TTypestate > { if ( ! IS_PRODUCTION ) { warn ( this . status !== InterpreterStatus . NotStarted , `Attempted to read state from uninitialized service '${ this . id }'. Make sure the service is started first.` ) ; } return this . _state ! ; } public static interpret = interpret ; param state param actionsConfig public execute ( state , actionsConfig ? ) { for ( const action of state . actions ) { this . exec ( action , state , actionsConfig ) ; } } private update ( state , _event ) { state . _sessionid = this . sessionId ; this . _state = state ; if ( this . options . execute ) { this . execute ( this . state ) ; } this . children . forEach ( ( child ) => { this . state . children [ child . id ] = child ; } ) ; if ( this . devTools ) { this . devTools . send ( _event . data , state ) ; } if ( state . event ) { for ( const listener of this . eventListeners ) { listener ( state . event ) ; } } for ( const listener of this . listeners ) { listener ( state , state . event ) ; } for ( const contextListener of this . contextListeners ) { contextListener ( this . state . context , this . state . history ? this . state . history . context : undefined ) ; } const isDone = isInFinalState ( state . configuration || [ ] , this . machine ) ; if ( this . state . configuration && isDone ) { const finalChildStateNode = state . configuration . find ( ( sn ) => sn . type === 'final' && sn . parent === this . machine ) ; const doneData = finalChildStateNode && finalChildStateNode . doneData ? mapContext ( finalChildStateNode . doneData , state . context , _event ) : undefined ; for ( const listener of this . doneListeners ) { listener ( doneInvoke ( this . id , doneData ) ) ; } this . stop ( ) ; } } public onTransition ( listener ) { this . listeners . add ( listener ) ; if ( this . status === InterpreterStatus . Running ) { listener ( this . state , this . state . event ) ; } return this ; } public subscribe ( nextListener ? , errorListener ? , completeListener ? ) ; public subscribe ( observer ) ; public subscribe ( nextListenerOrObserver ? , _ ? , completeListener ? ) { if ( ! nextListenerOrObserver ) { return { unsubscribe : ( ) => void 0 } ; } let listener ; let resolvedCompleteListener = completeListener ; if ( typeof nextListenerOrObserver === 'function' ) { listener = nextListenerOrObserver ; } else { listener = nextListenerOrObserver . next . bind ( nextListenerOrObserver ) ; resolvedCompleteListener = nextListenerOrObserver . complete . bind ( nextListenerOrObserver ) ; } this . listeners . add ( listener ) ; if ( this . status === InterpreterStatus . Running ) { listener ( this . state ) ; } if ( resolvedCompleteListener ) { this . onDone ( resolvedCompleteListener ) ; } return { unsubscribe : ( ) => { listener && this . listeners . delete ( listener ) ; resolvedCompleteListener && this . doneListeners . delete ( resolvedCompleteListener ) ; } } ; } param listener public onEvent ( listener ) { this . eventListeners . add ( listener ) ; return this ; } param listener public onSend ( listener ) { this . sendListeners . add ( listener ) ; return this ; } param listener public onChange ( listener ) { this . contextListeners . add ( listener ) ; return this ; } param listener public onStop ( listener ) { this . stopListeners . add ( listener ) ; return this ; } param listener public onDone ( listener ) { this . doneListeners . add ( listener ) ; return this ; } param listener public off ( listener ) { this . listeners . delete ( listener ) ; this . eventListeners . delete ( listener ) ; this . sendListeners . delete ( listener ) ; this . stopListeners . delete ( listener ) ; this . doneListeners . delete ( listener ) ; this . contextListeners . delete ( listener ) ; return this ; } /**
     * Alias for Interpreter.prototype.start
     */ public init = this . start ; param initialState public start ( initialState ? ) { if ( this . status === InterpreterStatus . Running ) { return this ; } registry . register ( this . sessionId , this as Actor ) ; this . initialized = true ; this . status = InterpreterStatus . Running ; const resolvedState = initialState === undefined ? this . initialState : serviceScope . provide ( this , ( ) => { return isState < TContext , TEvent , TStateSchema , TTypestate > ( initialState ) ? this . machine . resolveState ( initialState ) : this . machine . resolveState ( State . from ( initialState , this . machine . context ) ) ; } ) ; if ( this . options . devTools ) { this . attachDev ( ) ; } this . scheduler . initialize ( ( ) => { this . update ( resolvedState , initEvent as SCXML . Event < TEvent > ) ; } ) ; return this ; } /**
     * Stops the interpreter and unsubscribe all listeners.
     *
     * This will also notify the `onStop` listeners.
     */ public stop ( ) { for ( const listener of this . listeners ) { this . listeners . delete ( listener ) ; } for ( const listener of this . stopListeners ) { listener ( ) ; this . stopListeners . delete ( listener ) ; } for ( const listener of this . contextListeners ) { this . contextListeners . delete ( listener ) ; } for ( const listener of this . doneListeners ) { this . doneListeners . delete ( listener ) ; } if ( ! this . initialized ) { return this ; } [ ... this . state . configuration ] . sort ( ( a , b ) => b . order - a . order ) . forEach ( ( stateNode ) => { for ( const action of stateNode . definition . exit ) { this . exec ( action , this . state ) ; } } ) ; this . children . forEach ( ( child ) => { if ( isFunction ( child . stop ) ) { child . stop ( ) ; } } ) ; for ( const key of keys ( this . delayedEventsMap ) ) { this . clock . clearTimeout ( this . delayedEventsMap [ key ] ) ; } this . scheduler . clear ( ) ; this . initialized = false ; this . status = InterpreterStatus . Stopped ; registry . free ( this . sessionId ) ; return this ; } param event public send = ( event , payload ? ) : State < TContext , TEvent , TStateSchema , TTypestate > => { if ( isArray ( event ) ) { this . batch ( event ) ; return this . state ; } const _event = toSCXMLEvent ( toEventObject ( event as Event < TEvent > , payload ) ) ; if ( this . status === InterpreterStatus . Stopped ) { if ( ! IS_PRODUCTION ) { warn ( false , `Event "${ _event . name }" was sent to stopped service "${ this . machine . id }". This service has already reached its final state, and will not transition.\nEvent: ${ JSON . stringify ( _event . data ) }` ) ; } return this . state ; } if ( this . status !== InterpreterStatus . Running && ! this . options . deferEvents ) { throw new Error ( `Event "${ _event . name }" was sent to uninitialized service "${ this . machine . id }". Make sure .start() is called for this service, or set { deferEvents: true } in the service options.\nEvent: ${ JSON . stringify ( _event . data ) }` ) ; } this . scheduler . schedule ( ( ) => { this . forward ( _event ) ; const nextState = this . nextState ( _event ) ; this . update ( nextState , _event ) ; } ) ; return this . _state ! ; } ; private batch ( events ) { if ( this . status === InterpreterStatus . NotStarted && this . options . deferEvents ) { if ( ! IS_PRODUCTION ) { warn ( false , `${ events . length } event(s) were sent to uninitialized service "${ this . machine . id }" and are deferred. Make sure .start() is called for this service.\nEvent: ${ JSON . stringify ( event ) }` ) ; } } else if ( this . status !== InterpreterStatus . Running ) { throw new Error ( `${ events . length } event(s) were sent to uninitialized service "${ this . machine . id }". Make sure .start() is called for this service, or set { deferEvents: true } in the service options.` ) ; } this . scheduler . schedule ( ( ) => { let nextState = this . state ; let batchChanged = false ; const batchedActions = [ ] ; for ( const event of events ) { const _event = toSCXMLEvent ( event ) ; this . forward ( _event ) ; nextState = serviceScope . provide ( this , ( ) => { return this . machine . transition ( nextState , _event ) ; } ) ; batchedActions . push ( ... ( nextState . actions . map ( ( a ) => bindActionToState ( a , nextState ) ) as Array < ActionObject < TContext , TEvent > > ) ) ; batchChanged = batchChanged || ! ! nextState . changed ; } nextState . changed = batchChanged ; nextState . actions = batchedActions ; this . update ( nextState , toSCXMLEvent ( events [ events . length - 1 ] ) ) ; } ) ; } param event public sender ( event ) { return this . send . bind ( this , event ) ; } private sendTo = ( event , to ) => { const isParent = this . parent && ( to === SpecialTargets . Parent || this . parent . id === to ) ; const target = isParent ? this . parent : isString ( to ) ? this . children . get ( to as string ) || registry . get ( to as string ) : isActor ( to ) ? to : undefined ; if ( ! target ) { if ( ! isParent ) { throw new Error ( `Unable to send event to child '${ to }' from service '${ this . id }'.` ) ; } if ( ! IS_PRODUCTION ) { warn ( false , `Service '${ this . id }' has no parent: unable to send event ${ event . type }` ) ; } return ; } if ( 'machine' in target ) { ( target as AnyInterpreter ) . send ( { ... event , name : event . name === actionTypes . error ? `${ error ( this . id ) }` : event . name , origin : this . sessionId } ) ; } else { target . send ( event . data ) ; } } ; param event public nextState ( event ) { const _event = toSCXMLEvent ( event ) ; if ( _event . name . indexOf ( actionTypes . errorPlatform ) === 0 && ! this . state . nextEvents . some ( ( nextEvent ) => nextEvent . indexOf ( actionTypes . errorPlatform ) === 0 ) ) { throw ( _event . data as any ) . data ; } const nextState = serviceScope . provide ( this , ( ) => { return this . machine . transition ( this . state , _event ) ; } ) ; return nextState ; } private forward ( event ) { for ( const id of this . forwardTo ) { const child = this . children . get ( id ) ; if ( ! child ) { throw new Error ( `Unable to forward event '${ event }' from interpreter '${ this . id }' to nonexistant child '${ id }'.` ) ; } child . send ( event ) ; } } private defer ( sendAction ) { this . delayedEventsMap [ sendAction . id ] = this . clock . setTimeout ( ( ) => { if ( sendAction . to ) { this . sendTo ( sendAction . _event , sendAction . to ) ; } else { this . send ( ( sendAction as SendActionObject < TContext , TEvent , TEvent > ) . _event ) ; } } , sendAction . delay as number ) ; } private cancel ( sendId ) { this . clock . clearTimeout ( this . delayedEventsMap [ sendId ] ) ; delete this . delayedEventsMap [ sendId ] ; } private exec ( action , state , actionFunctionMap = this . machine . options . actions ) { const { context , _event } = state ; const actionOrExec = action . exec || getActionFunction ( action . type , actionFunctionMap ) ; const exec = isFunction ( actionOrExec ) ? actionOrExec : actionOrExec ? actionOrExec . exec : action . exec ; if ( exec ) { try { return exec ( context , _event . data , { action , state : this . state , _event } ) ; } catch ( err ) { if ( this . parent ) { this . parent . send ( { type : 'xstate.error' , data : err } as EventObject ) ; } throw err ; } } switch ( action . type ) { case actionTypes . send : const sendAction = action as SendActionObject < TContext , TEvent > ; if ( typeof sendAction . delay === 'number' ) { this . defer ( sendAction ) ; return ; } else { if ( sendAction . to ) { this . sendTo ( sendAction . _event , sendAction . to ) ; } else { this . send ( ( sendAction as SendActionObject < TContext , TEvent , TEvent > ) . _event ) ; } } break ; case actionTypes . cancel : this . cancel ( ( action as CancelAction ) . sendId ) ; break ; case actionTypes . start : { if ( this . status !== InterpreterStatus . Running ) { return ; } const activity = ( action as ActivityActionObject < TContext , TEvent > ) . activity as InvokeDefinition < TContext , TEvent > ; if ( ! this . state . activities [ activity . id || activity . type ] ) { break ; } if ( activity . type === ActionTypes . Invoke ) { const invokeSource = toInvokeSource ( activity . src ) ; const serviceCreator = this . machine . options . services ? this . machine . options . services [ invokeSource . type ] : undefined ; const { id , data } = activity ; if ( ! IS_PRODUCTION ) { warn ( ! ( 'forward' in activity ) , `\`forward\` property is deprecated (found in invocation of '${ activity . src }' in in machine '${ this . machine . id }'). ` + `Please use \`autoForward\` instead.` ) ; } const autoForward = 'autoForward' in activity ? activity . autoForward : ! ! activity . forward ; if ( ! serviceCreator ) { if ( ! IS_PRODUCTION ) { warn ( false , `No service found for invocation '${ activity . src }' in machine '${ this . machine . id }'.` ) ; } return ; } const resolvedData = data ? mapContext ( data , context , _event ) : undefined ; if ( typeof serviceCreator === 'string' ) { return ; } let source = isFunction ( serviceCreator ) ? serviceCreator ( context , _event . data , { data : resolvedData , src : invokeSource , meta : activity . meta } ) : serviceCreator ; if ( ! source ) { return ; } let options ; if ( isMachine ( source ) ) { source = resolvedData ? source . withContext ( resolvedData ) : source ; options = { autoForward } ; } this . spawn ( source , id , options ) ; } else { this . spawnActivity ( activity ) ; } break ; } case actionTypes . stop : { this . stopChild ( ( action as StopActionObject ) . activity . id ) ; break ; } case actionTypes . log : const { label , value } = action ; if ( label ) { this . logger ( label , value ) ; } else { this . logger ( value ) ; } break ; default : if ( ! IS_PRODUCTION ) { warn ( false , `No implementation found for action type '${ action . type }'` ) ; } break ; } return undefined ; } private removeChild ( childId ) { this . children . delete ( childId ) ; this . forwardTo . delete ( childId ) ; delete this . state ?. children [ childId ] ; } private stopChild ( childId ) { const child = this . children . get ( childId ) ; if ( ! child ) { return ; } this . removeChild ( childId ) ; if ( isFunction ( child . stop ) ) { child . stop ( ) ; } } public spawn ( entity , name , options ? ) { if ( isPromiseLike ( entity ) ) { return this . spawnPromise ( Promise . resolve ( entity ) , name ) ; } else if ( isFunction ( entity ) ) { return this . spawnCallback ( entity as InvokeCallback , name ) ; } else if ( isSpawnedActor ( entity ) ) { return this . spawnActor ( entity , name ) ; } else if ( isObservable < TEvent > ( entity ) ) { return this . spawnObservable ( entity , name ) ; } else if ( isMachine ( entity ) ) { return this . spawnMachine ( entity , { ... options , id : name } ) ; } else if ( isBehavior ( entity ) ) { return this . spawnBehavior ( entity , name ) ; } else { throw new Error ( `Unable to spawn entity "${ name }" of type "${ typeof entity }".` ) ; } } public spawnMachine < TChildContext , TChildStateSchema , TChildEvent extends EventObject > ( machine , options = { } ) { const childService = new Interpreter ( machine , { ... this . options , parent : this , id : options . id || machine . id } ) ; const resolvedOptions = { ... DEFAULT_SPAWN_OPTIONS , ... options } ; if ( resolvedOptions . sync ) { childService . onTransition ( ( state ) => { this . send ( actionTypes . update as any , { state , id : childService . id } ) ; } ) ; } const actor = childService ; this . children . set ( childService . id , actor ) ; if ( resolvedOptions . autoForward ) { this . forwardTo . add ( childService . id ) ; } childService . onDone ( ( doneEvent ) => { this . removeChild ( childService . id ) ; this . send ( toSCXMLEvent ( doneEvent as any , { origin : childService . id } ) ) ; } ) . start ( ) ; return actor ; } private spawnBehavior < TActorEvent extends EventObject , TEmitted > ( behavior , id ) { const actorRef = spawnBehavior ( behavior , { id , parent : this } ) ; this . children . set ( id , actorRef ) ; return actorRef ; } private spawnPromise < T > ( promise , id ) { let canceled = false ; let resolvedData ; promise . then ( ( response ) => { if ( ! canceled ) { resolvedData = response ; this . removeChild ( id ) ; this . send ( toSCXMLEvent ( doneInvoke ( id , response ) as any , { origin : id } ) ) ; } } , ( errorData ) => { if ( ! canceled ) { this . removeChild ( id ) ; const errorEvent = error ( id , errorData ) ; try { this . send ( toSCXMLEvent ( errorEvent as any , { origin : id } ) ) ; } catch ( error ) { reportUnhandledExceptionOnInvocation ( errorData , error , id ) ; if ( this . devTools ) { this . devTools . send ( errorEvent , this . state ) ; } if ( this . machine . strict ) { this . stop ( ) ; } } } } ) ; const actor = { id , send : ( ) => void 0 , subscribe : ( next , handleError ? , complete ? ) => { const observer = toObserver ( next , handleError , complete ) ; let unsubscribed = false ; promise . then ( ( response ) => { if ( unsubscribed ) { return ; } observer . next ( response ) ; if ( unsubscribed ) { return ; } observer . complete ( ) ; } , ( err ) => { if ( unsubscribed ) { return ; } observer . error ( err ) ; } ) ; return { unsubscribe : ( ) => ( unsubscribed = true ) } ; } , stop : ( ) => { canceled = true ; } , toJSON ( ) { return { id } ; } , getSnapshot : ( ) => resolvedData , ... interopSymbols } ; this . children . set ( id , actor ) ; return actor ; } private spawnCallback ( callback , id ) { let canceled = false ; const receivers = new Set < ( e : EventObject ) => void > ( ) ; const listeners = new Set < ( e : EventObject ) => void > ( ) ; let emitted ; const receive = ( e ) => { emitted = e ; listeners . forEach ( ( listener ) => listener ( e ) ) ; if ( canceled ) { return ; } this . send ( toSCXMLEvent ( e , { origin : id } ) ) ; } ; let callbackStop ; try { callbackStop = callback ( receive , ( newListener ) => { receivers . add ( newListener ) ; } ) ; } catch ( err ) { this . send ( error ( id , err ) as any ) ; } if ( isPromiseLike ( callbackStop ) ) { return this . spawnPromise ( callbackStop as Promise < any > , id ) ; } const actor = { id , send : ( event ) => receivers . forEach ( ( receiver ) => receiver ( event ) ) , subscribe : ( next ) => { listeners . add ( next ) ; return { unsubscribe : ( ) => { listeners . delete ( next ) ; } } ; } , stop : ( ) => { canceled = true ; if ( isFunction ( callbackStop ) ) { callbackStop ( ) ; } } , toJSON ( ) { return { id } ; } , getSnapshot : ( ) => emitted , ... interopSymbols } ; this . children . set ( id , actor ) ; return actor ; } private spawnObservable < T extends TEvent > ( source , id ) { let emitted ; const subscription = source . subscribe ( ( value ) => { emitted = value ; this . send ( toSCXMLEvent ( value , { origin : id } ) ) ; } , ( err ) => { this . removeChild ( id ) ; this . send ( toSCXMLEvent ( error ( id , err ) as any , { origin : id } ) ) ; } , ( ) => { this . removeChild ( id ) ; this . send ( toSCXMLEvent ( doneInvoke ( id ) as any , { origin : id } ) ) ; } ) ; const actor = { id , send : ( ) => void 0 , subscribe : ( next , handleError ? , complete ? ) => { return source . subscribe ( next , handleError , complete ) ; } , stop : ( ) => subscription . unsubscribe ( ) , getSnapshot : ( ) => emitted , toJSON ( ) { return { id } ; } , ... interopSymbols } ; this . children . set ( id , actor ) ; return actor ; } private spawnActor < T extends ActorRef < any > > ( actor , name ) { this . children . set ( name , actor ) ; return actor ; } private spawnActivity ( activity ) { const implementation = this . machine . options && this . machine . options . activities ? this . machine . options . activities [ activity . type ] : undefined ; if ( ! implementation ) { if ( ! IS_PRODUCTION ) { warn ( false , `No implementation found for activity '${ activity . type }'` ) ; } return ; } const dispose = implementation ( this . state . context , activity ) ; this . spawnEffect ( activity . id , dispose ) ; } private spawnEffect ( id , dispose ? ) { this . children . set ( id , { id , send : ( ) => void 0 , subscribe : ( ) => { return { unsubscribe : ( ) => void 0 } ; } , stop : dispose || undefined , getSnapshot : ( ) => undefined , toJSON ( ) { return { id } ; } , ... interopSymbols } ) ; } private attachDev ( ) { const global = getGlobal ( ) ; if ( this . options . devTools && global ) { if ( ( global as any ) . __REDUX_DEVTOOLS_EXTENSION__ ) { const devToolsOptions = typeof this . options . devTools === 'object' ? this . options . devTools : undefined ; this . devTools = ( global as any ) . __REDUX_DEVTOOLS_EXTENSION__ . connect ( { name : this . id , autoPause : true , stateSanitizer : ( state ) : object => { return { value : state . value , context : state . context , actions : state . actions } ; } , ... devToolsOptions , features : { jump : false , skip : false , ... ( devToolsOptions ? ( devToolsOptions as any ) . features : undefined ) } } , this . machine ) ; this . devTools . init ( this . state ) ; } registerService ( this ) ; } } public toJSON ( ) { return { id : this . id } ; } public [ symbolObservable ] ( ) { return this ; } public [ Symbol . observable ] ( ) { return this ; } public getSnapshot ( ) { if ( this . status === InterpreterStatus . NotStarted ) { return this . initialState ; } return this . _state ! ; } } const resolveSpawnOptions = ( nameOrOptions ? ) => { if ( isString ( nameOrOptions ) ) { return { ... DEFAULT_SPAWN_OPTIONS , name : nameOrOptions } ; } return { ... DEFAULT_SPAWN_OPTIONS , name : uniqueId ( ) , ... nameOrOptions } ; } ; export function spawn < T extends Behavior < any , any > > ( entity , nameOrOptions ? ) ; export function spawn < TC , TE extends EventObject > ( entity , nameOrOptions ? ) ; export function spawn ( entity , nameOrOptions ? ) ; export function spawn ( entity , nameOrOptions ? ) { const resolvedOptions = resolveSpawnOptions ( nameOrOptions ) ; return serviceScope . consume ( ( service ) => { if ( ! IS_PRODUCTION ) { const isLazyEntity = isMachine ( entity ) || isFunction ( entity ) ; warn ( ! ! service || isLazyEntity , `Attempted to spawn an Actor (ID: "${ isMachine ( entity ) ? entity . id : 'undefined' }") outside of a service. This will have no effect.` ) ; } if ( service ) { return service . spawn ( entity , resolvedOptions . name , resolvedOptions ) ; } else { return createDeferredActor ( entity , resolvedOptions . name ) ; } } ) ; } param machine param options export function interpret < TContext = DefaultContext , TStateSchema extends StateSchema = any , TEvent extends EventObject = EventObject , TTypestate extends Typestate < TContext > = { value : any ; context : TContext ; } > ( machine , options ? ) { const interpreter = new Interpreter < TContext , TStateSchema , TEvent , TTypestate > ( machine , options ) ; return interpreter ; }