import { Effect, type Layer, ManagedRuntime, Predicate, type Runtime } from "effect" import * as React from "react" export const TypeId: unique symbol = Symbol.for("effect-fc/ReactRuntime") export type TypeId = typeof TypeId export interface ReactRuntime { new(_: never): {} readonly [TypeId]: TypeId readonly runtime: ManagedRuntime.ManagedRuntime readonly context: React.Context> } const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const) export const isReactRuntime = (u: unknown): u is ReactRuntime => Predicate.hasProperty(u, TypeId) export const make = ( layer: Layer.Layer, memoMap?: Layer.MemoMap, ): ReactRuntime => Object.setPrototypeOf( Object.assign(function() {}, { runtime: ManagedRuntime.make(layer, memoMap), context: React.createContext>(null!), }), ReactRuntimeProto, ) export namespace Provider { export interface Props extends React.SuspenseProps { readonly runtime: ReactRuntime readonly children?: React.ReactNode } } export const Provider = ( { runtime, children, ...suspenseProps }: Provider.Props ): React.ReactNode => { const promise = React.useMemo(() => Effect.runPromise(runtime.runtime.runtimeEffect), [runtime]) return React.createElement( React.Suspense, suspenseProps, React.createElement(ProviderInner, { runtime, promise, children }), ) } namespace ProviderInner { export interface Props { readonly runtime: ReactRuntime readonly promise: Promise> readonly children?: React.ReactNode } } const ProviderInner = ( { runtime, promise, children }: ProviderInner.Props ): React.ReactNode => React.createElement( runtime.context, { value: React.use(promise) }, children, )