import { Exact, IfEmptyObject, TaggedUnion } from 'type-fest';

interface ContextOptions {
    createError?: (args: {
        capability: string;
    }) => unknown;
}
declare function createActor<Actor extends object>(): {
    build<D>(builder: (cap: ReturnType<typeof createCapability<Actor>>) => D): (actor: Actor, opts?: ContextOptions) => D;
};
declare function createCapability<Actor>(actor: Actor, opts?: ContextOptions): {
    subject: <Subject>() => {
        define: <const Capability extends string, Args extends {} | Exact<Partial<Record<Capability, any>>, Args> = {}, ArgsType = { [K in keyof Args]: Args[K] extends (...args: any[]) => any ? ReturnType<Args[K]> : Args[K]; }>(resolver: (ctx: {
            actor: Actor;
            subject: Subject;
            args: Partial<ArgsType>;
        }) => Generator<Capability[], Capability[], any>, args?: Args | undefined) => Omit<{
            subject: (subject: Subject) => {
                can: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                    throw: () => void;
                    check: () => boolean;
                };
                list(args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>): Capability[];
            };
            subjects: <const S>(subjects: S[], ...args: S extends Subject ? [] : [mapper: (s: S) => Subject]) => {
                canSome: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                    check: () => boolean;
                    throw: () => boolean;
                };
                canEvery: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                    check: () => boolean;
                    throw: () => void;
                };
                filter: <const FilterCaps extends Capability>(capabilities: FilterCaps[], args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>) => S[];
            };
            can: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                throw: () => void;
                check: () => boolean;
            };
            list(args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>): Capability[];
        }, Subject extends undefined ? "subject" | "subjects" : "can">;
    };
    define: <const Capability extends string, Args extends {} | Exact<Partial<Record<Capability, any>>, Args> = {}, ArgsType = { [K in keyof Args]: Args[K] extends (...args: any[]) => any ? ReturnType<Args[K]> : Args[K]; }>(resolver: (ctx: {
        actor: Actor;
        subject: undefined;
        args: Partial<ArgsType>;
    }) => Generator<Capability[], Capability[], any>, args?: Args | undefined) => Omit<{
        subject: (subject: undefined) => {
            can: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                throw: () => void;
                check: () => boolean;
            };
            list(args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>): Capability[];
        };
        subjects: <const S>(subjects: S[], ...args: S extends undefined ? [] : [mapper: (s: S) => undefined]) => {
            canSome: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                check: () => boolean;
                throw: () => boolean;
            };
            canEvery: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
                check: () => boolean;
                throw: () => void;
            };
            filter: <const FilterCaps extends Capability>(capabilities: FilterCaps[], args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>) => S[];
        };
        can: <Capability_1 extends Capability>(capability: Capability_1, ...args: Capability_1 extends keyof ArgsType ? ArgsType[Capability_1] extends undefined ? [] : [args: ArgsType[Capability_1]] : []) => {
            throw: () => void;
            check: () => boolean;
        };
        list(args: IfEmptyObject<ArgsType, void, Partial<ArgsType>>): Capability[];
    }, "subject" | "subjects">;
};
declare class MissingCapabilityError extends Error {
    constructor(capability: string);
}

declare function arg<T extends object>(): T;
type Modes<T extends Record<string, Record<string, unknown>>> = TaggedUnion<'__mode', T>;
declare function mode<const K extends string, T extends Record<string, unknown>>(key: K, obj: T): {
    __mode: K;
} & T;

export { type ContextOptions, MissingCapabilityError, type Modes, arg, createActor, mode };
