import { catchError, map, Observable, Subject, tap, type OperatorFunction } from 'rxjs' import type { OrchModel } from '../model' import { performer } from './performer' export type ValidEpicAction = null | (() => void) export type EpicFactory
= (params: { payload$: Observable
action: EpicAction
state$: ToObservableState
}) => Observable (func: (...params: P) => void, ...params: P): Exclude (func: (payload: P) => void): OperatorFunction
}
export type ToObservableState = (func: (...params: P) => void, ...params: P) {
return () => func(...params)
},
{
map (func: (payload: P) => void): OperatorFunction {
return map((value) => action(func, value))
},
},
)
const state$: ToObservableState = (model) => {
return new Observable((observer) => {
observer.next(model.getState())
return model.on.change(() => {
observer.next(model.getState())
})
})
}
export function epic (
model: OrchModel ,
config?: EpicConfig,
) {
function init() {
const subject = new Subject ()
const subscription = factory({ payload$: subject.asObservable(), action, state$ })
.pipe(
tap((epicAction) =>
(Array.isArray(epicAction) ? epicAction : [epicAction]).forEach((fn) => fn?.()),
),
logAngIgnoreError(config?.factoryToLog ?? factory),
)
.subscribe()
return { subject, subscription }
}
return performer (model, () => {
const { subject, subscription } = init()
return {
next(payload) {
subject.next(payload)
},
dispose() {
subject.complete()
subscription.unsubscribe()
},
}
})
}
function logAngIgnoreError(factory: unknown) {
return catchError((err, caught) => {
/* eslint-disable no-console */
console.group('[Orch]: Epic error')
console.log(factory)
console.error(err)
console.groupEnd()
/* eslint-enable no-console */
return caught
})
}
(model: OrchModel) => Observable
const action: EpicAction = Object.assign(
function action