@donverduyn/react-runtime
Version:
effect-ts react integration
177 lines (176 loc) • 7.48 kB
TypeScript
import type React from 'react';
import type { Layer, ManagedRuntime } from 'effect';
import type { MergeLeft } from 'effect/Types';
import type { Booleans, Call, Objects, Tuples } from 'hotscript';
import type { IsStringLiteral, Simplify, Tagged } from 'type-fest';
import type { createUse } from '@/hooks/useRuntimeApi/hooks/use';
import type { createFn } from '@/hooks/useRuntimeApi/hooks/useFn';
import type { createRun } from '@/hooks/useRuntimeApi/hooks/useRun';
import type { createPush } from 'hooks/useRuntimeApi/hooks/usePush';
import type { PropService } from 'utils/effect';
export type ScopeId = Tagged<string, 'ScopeId'>;
export type InstId = Tagged<string, 'InstId'>;
export type DeclId = Tagged<string, 'DeclId'>;
export type DeclarationId = Tagged<string, 'DeclarationId'>;
export type ComponentId = Tagged<string, 'ComponentId'>;
export type RegisterId = Tagged<string, 'RegisterId'>;
export type RuntimeKey = symbol;
export type RuntimeId = Tagged<string, 'RuntimeId'>;
export type ProviderId = Tagged<string, 'ProviderId'>;
export type InstanceId = Tagged<string, 'InstanceId'>;
export type ComponentMeta = {
name: string;
};
export declare const ID_PROP = "_id";
export declare const DRYRUN_ID_PROP = "_dryRunId";
export declare const PROVIDERS_PROP = "_providers";
export declare const COMPONENT_PROP = "_component";
export declare const PROPS_PROP = "_props";
export declare const UPSTREAM_PROP = "_upstream";
export declare const ERROR_PROP = "_error";
export type RuntimeApi<R> = {
instance: RuntimeInstance<R>['runtime'];
use: ReturnType<typeof createUse<R>>;
useFn: ReturnType<typeof createFn<R>>;
usePush: ReturnType<typeof createPush<R>>;
useRun: ReturnType<typeof createRun<R>>;
};
export type RuntimeApiFactory<R> = {
create: (module: RuntimeContext<R, never, PropService>, instances: Map<RuntimeKey, RuntimeInstance<any>>) => RuntimeApi<R>;
createInert: (stub: unknown) => RuntimeApi<R>;
};
export type RuntimeConfig = {
debug: boolean;
postUnmountTTL: number;
env: 'prod' | 'dev';
replace: boolean;
cleanupPolicy: 'onUnmount' | 'immediate';
};
export type RuntimeContext<R, E = never, A = never> = {
key: RuntimeKey;
name: string;
layer: Layer.Layer<R, E, A>;
};
export type RuntimePayload<R, P extends Record<string, unknown>> = {
providerId: string;
index: number;
context: RuntimeContext<R, never, PropService>;
config: Partial<RuntimeConfig>;
props: P;
};
export type RuntimeInstance<R, P = object> = {
id: InstanceId;
runtime: ManagedRuntime.ManagedRuntime<R, never>;
config: RuntimeConfig;
propProxy: Subscribable<NoInfer<P>> & P;
};
export type IdProp = {
readonly id: string;
};
export type Extensible<T extends Record<PropertyKey, unknown>> = T & Record<PropertyKey, unknown>;
export type SubscribeFn<T> = (value: T) => void;
export type UnsubscribeFn = () => void;
export type Subscribable<T> = {
subscribe: (key: keyof T | PropertyKey, fn: SubscribeFn<T[keyof T]>) => UnsubscribeFn;
value: T;
};
export type IsPrimitiveString<T> = [T] extends [string] ? IsStringLiteral<T> extends true ? false : true : false;
export type SafeKeys<T extends PropertyKey> = IsStringLiteral<T> extends true ? T : never;
export type ResultProps<CProps, ExtraProps extends Record<PropertyKey, unknown>> = Readonly<Partial<IdProp & Pick<ExtraProps, keyof CProps>> & Omit<CProps, SafeKeys<keyof ExtraProps>>>;
export type ExtensibleProps<CProps> = Extensible<Partial<IdProp & CProps>>;
export type UpstreamProviderApi<P> = {
inject: <R>(module: RuntimeContext<R, never, PropService>) => RuntimeApi<R>;
props: P;
};
export type UpstreamProviderFn<CProps, TResult = unknown> = (api: UpstreamProviderApi<MergeLeft<IdProp, CProps>>) => TResult;
export type ProviderApi<R, P = object> = {
configure: (config?: Partial<RuntimeConfig>) => RuntimeApi<R>;
runtime: RuntimeApi<R>;
inject: <R>(module: RuntimeContext<R, never, PropService>) => RuntimeApi<R>;
props: P;
};
export type ProviderFn<R, CProps, TResult = unknown> = (api: ProviderApi<R, MergeLeft<IdProp, CProps>>) => TResult;
export type PropsFn<CProps, TResult = unknown> = (props: MergeLeft<IdProp, CProps>) => TResult;
export type ProviderEntryType = 'runtime' | 'upstream' | 'props';
export type ProviderEntry<R, C extends React.FC<any>, P = any> = {
id: ProviderId;
type: 'runtime';
module: RuntimeContext<R, never, PropService>;
fn?: ProviderFn<R, C, P> | ProviderFn<R, C, undefined> | undefined;
} | {
id: ProviderId;
type: 'upstream';
module?: RuntimeContext<R, never, PropService> | undefined;
fn: ProviderFn<R, C, P> | ProviderFn<R, C>;
} | {
id: ProviderId;
type: 'props';
fn: PropsFn<C, P>;
};
export type ResolvedProviderEntry<R, C extends React.FC<any>, P> = ProviderEntry<R, C, P> & {
level: number;
index: number;
};
export type ExtractStaticComponent<T> = T extends {
[COMPONENT_PROP]: infer C;
} ? C extends (props: infer P) => any ? React.FC<Simplify<P>> : never : T;
export type ExtractStaticProviders<T> = T extends {
[PROVIDERS_PROP]: infer R;
} ? R extends unknown[] ? R : never : [];
export type ExtractStaticProps<T> = T extends {
[PROPS_PROP]: infer P;
} ? P : Record<never, never>;
export type ExtractProps<C extends React.FC<any>> = React.ComponentProps<C> & ExtractStaticProps<C>;
export type ExtractStaticUpstream<T> = T extends {
[UPSTREAM_PROP]: infer U;
} ? U extends unknown[] ? U : never : [];
export type ExtractStaticError<T> = T extends {
[ERROR_PROP]: infer U;
} ? U extends unknown[] ? U : never : [];
export type UnwrapRuntime<T> = T extends {
module: infer R;
} ? R : T;
type ExtractReference<T> = UnwrapRuntime<T> extends {
reference: () => infer R;
} ? R : never;
declare const UpstreamSymbol: unique symbol;
type UpstreamBrand = {
readonly [UpstreamSymbol]: never;
};
export type Up<T> = T & UpstreamBrand;
export type KeepUpstream<T> = Call<Tuples.Filter<Booleans.Extends<{
[UpstreamSymbol]: true;
}>>, T>;
type DownstreamBrand = {
readonly [UpstreamSymbol]: false;
};
export type Down<T> = T & DownstreamBrand;
export type FilterReference<T> = Call<Tuples.Map<Objects.Get<'type'>>, T>;
type ExtractProviders<T> = T extends {
[PROVIDERS_PROP]?: infer R;
} ? R : never;
type Includes<T extends readonly unknown[], V> = T extends [
infer Head,
...infer Rest
] ? [V] extends [Head] ? true : Includes<Rest, V> : false;
type PushUnique<T extends readonly unknown[], V> = Includes<T, V> extends true ? T : [...T, V];
type Reverse<T> = Call<Tuples.Reverse, T>;
type Unique<T extends any[], Acc extends any[] = []> = T extends [
infer Head,
...infer Tail
] ? Head extends Acc[number] ? Unique<Tail, Acc> : Unique<Tail, [...Acc, Head]> : Acc;
export type CollectProviders<Component, Seen extends unknown[] = [], Acc extends unknown[] = []> = ExtractProviders<Component> extends readonly [infer Head, ...infer Tail] ? ExtractReference<Head> extends infer Ref ? Ref extends object ? Ref extends Seen[number] ? CollectProviders<{
[PROVIDERS_PROP]?: Tail;
}, Seen, PushUnique<Acc, Head>> : CollectProviders<{
[PROVIDERS_PROP]?: Tail;
}, [
...Seen,
Ref
], PushUnique<[
...Acc,
...CollectProviders<Ref, [...Seen, Ref], Acc>
], Head>> : CollectProviders<{
[PROVIDERS_PROP]?: Tail;
}, Seen, PushUnique<Acc, Head>> : Acc : Acc;
export type TraverseDeps<T> = Reverse<Unique<CollectProviders<T>>>;
export {};