import * as Context from "effect/Context"; import type { Effect } from "effect/Effect"; import * as Layer from "effect/Layer"; import type { Provider, ProviderService } from "./provider.ts"; import type { InstanceId } from "./instance-id.ts"; export const isResource = (r: any): r is Resource => { return ( r && typeof r === "function" && "id" in r && "type" in r && "props" in r ); }; export type AnyResource = Resource; export interface IResource< Type extends string = string, ID extends string = string, Props = unknown, Attrs = unknown, Base = unknown, > { id: ID; type: Type; Props: unknown; props: Props; base: Base; /** @internal phantom */ attr: Attrs; } export interface Resource< Type extends string = string, ID extends string = string, Props = unknown, Attrs = unknown, Base = unknown, > extends IResource { new (): Resource; } export interface ResourceTags> { of>(service: S): S; tag: Provider; effect< Err, Req, ReadReq = never, DiffReq = never, PrecreateReq = never, CreateReq = never, UpdateReq = never, DeleteReq = never, >( eff: Effect< ProviderService< R, ReadReq, DiffReq, PrecreateReq, CreateReq, UpdateReq, DeleteReq >, Err, Req >, ): Layer.Layer< Provider, Err, Exclude< | Req | ReadReq | DiffReq | PrecreateReq | CreateReq | UpdateReq | DeleteReq, InstanceId > >; succeed< ReadReq = never, DiffReq = never, PrecreateReq = never, CreateReq = never, UpdateReq = never, DeleteReq = never, >( service: ProviderService< R, ReadReq, DiffReq, PrecreateReq, CreateReq, UpdateReq, DeleteReq >, ): Layer.Layer< Provider, never, Exclude< ReadReq | DiffReq | PrecreateReq | CreateReq | UpdateReq | DeleteReq, InstanceId > >; } export const Resource = Resource>( type: ReturnType["type"], ) => { const Tag = Context.Tag(type)(); const provider: ResourceTags> = { tag: Tag as any, effect: (eff) => Layer.effect(Tag, eff), succeed: (service: ProviderService>) => Layer.succeed(Tag, service), of: (service) => service, } as ResourceTags>; return Object.assign( function (id: string, props: any) { return class Resource { static readonly id = id; static readonly type = type; static readonly props = props; static readonly provider = provider; }; } as unknown as Ctor & { type: ReturnType["type"]; parent: ReturnType; new (): ReturnType & { parent: ReturnType; }; provider: typeof provider; }, { type: type, provider, }, ); };