/** * Context is an alternative implementation of Ref which is capable of traversing up * in a graph of to find if any ancestors contain the given value. This is allows sharing values * across otherwise isolated environments. * @since 0.11.0 */ import * as E from './Env' import * as EO from './EnvOption' import { flow, identity, pipe } from './function' import * as KV from './KV' import * as RS from './ReaderStream' import * as Ref from './Ref' import { SchedulerEnv } from './Scheduler' import { useReaderStream } from './Use' /** * Context is an extensions of Ref which traverse up in context to find the closest environment * which contains the expected value. * @since 0.11.0 * @categeory Model */ export interface Context extends Ref.Ref {} /** * @since 0.11.0 * @category Constructor */ export const fromKV = ( kv: KV.KV, ): Context & KV.KV => ({ ...kv, get: useKV(kv), has: pipe(kv, KV.has, KV.withProvider(kv)), set: flow(KV.set(kv), KV.withProvider(kv)), update: flow(KV.update(kv), KV.withProvider(kv)), remove: pipe(kv, KV.remove, KV.withProvider(kv)), values: pipe(KV.listenToValues(kv), KV.withProviderStream(kv)), }) /** * Allows subscribing to the updates ensuring the current KV receives all * updates from an Ancestor. * @since 0.9.2 * @category Combinator */ export function useKV(kv: KV.KV): E.Env { const useValues = useReaderStream() const useReplicateEvents = useReaderStream() return pipe( E.Do, E.bindW('currentRefs', () => KV.getEnv), E.bindW('providerRefs', () => KV.findKVProvider(kv)), E.bindW('value', ({ providerRefs }) => pipe( kv, KV.listenToValues, RS.useSome(providerRefs), useValues, EO.chainOptionK(identity), EO.getOrElseEW(() => pipe(kv, KV.get, E.useSome(providerRefs))), ), ), E.chainFirstW(({ currentRefs, providerRefs }) => pipe( kv, KV.listenTo, RS.useSome(providerRefs), RS.chainEnvK((event) => pipe({ ...event, fromAncestor: true }, KV.sendEvent, E.useSome(currentRefs)), ), useReplicateEvents, ), ), E.map(({ value }) => value), ) } /** * @since 0.13.7 * @category Constructor */ export const kv = flow(KV.make, fromKV)