//#region src/core/definitions.d.ts
interface ActionSpec {
  name: string;
  type?: unknown;
  required?: boolean;
}
type Action = string | ActionSpec;
/**
 * The full type of a permissions tree passed to `createPermix<D>()`.
 *
 * @example Flat
 * ```ts
 * type D = ['read', 'write']
 * ```
 *
 * @example One level
 * ```ts
 * type D = {
 *   post: ['create', 'read']
 *   user: ['invite']
 * }
 * ```
 *
 * @example Deeply nested
 * ```ts
 * type D = {
 *   workspace: {
 *     member: ['invite', 'remove']
 *     billing: ['view', 'update']
 *   }
 * }
 * ```
 */
type Definition = readonly Action[] | {
  [key: string]: Definition;
};
type ValidateDefinition<D extends Definition> = D & ([Extract<Definition, string>] extends [never] ? unknown : Extract<Definition, string>);
/** Resolves an {@link Action} to its string name. */
type ActionName<A extends Action> = A extends string ? A : A extends {
  name: infer N extends string;
} ? N : never;
//#endregion
//#region src/core/rules.d.ts
type ActionRule<A extends Action> = A extends {
  type: infer T;
  required: true;
} ? (data: T) => boolean : A extends {
  type: infer T;
} ? ((data?: T) => boolean) | boolean : boolean | (() => boolean);
/**
 * The shape of the object passed to `permix.setup()` (and produced by
 * {@link createRules}). It mirrors the `Definition` `D`: every leaf action
 * becomes either a `boolean` or a `(data) => boolean` validator.
 */
type Rules<D extends Definition> = D extends readonly Action[] ? { [E in D[number] as ActionName<E>]: ActionRule<E> } : { [K in keyof D]: D[K] extends Definition ? Rules<D[K]> : never };
/**
 * The JSON-safe form of {@link Rules}, where every leaf rule has been
 * collapsed to a plain `boolean`. Produced by `permix.dehydrate()` and
 * consumed by `permix.hydrate()`.
 */
type DehydratedState<D extends Definition> = D extends readonly Action[] ? { [E in D[number] as ActionName<E>]: boolean } : { [K in keyof D & string]: D[K] extends Definition ? DehydratedState<D[K]> : never };
/**
 * Recursively collapse a rules tree into its JSON-safe {@link DehydratedState}.
 *
 * Function-based rules are invoked once with no data; entity-required
 * validators that throw on `undefined` are treated as `false`.
 */
declare function dehydrateRules(node: unknown): unknown;
/**
 * Rebuild a {@link Rules} tree from a {@link DehydratedState} produced by
 * {@link dehydrateRules}. Only the serialized booleans are restored.
 */
declare function hydrateRules<D extends Definition>(state: DehydratedState<D>): Rules<D>;
/**
 * Build a typed {@link Rules} object for a given {@link Definition}.
 *
 * Returns the input unchanged — useful for declaring rules in a separate
 * location with full type inference.
 *
 * @example
 * ```ts
 * const rules = createRules<{ post: ['create', 'read'] }>({
 *   post: { create: true, read: false },
 * })
 *
 * permix.setup(rules)
 * ```
 */
declare function createRules<D extends Definition>(rules: Rules<D>): Rules<D>;
//#endregion
//#region src/core/permix.d.ts
type ActionArgs<A extends Action> = A extends {
  type: infer T;
  required: true;
} ? [T] : A extends {
  type: infer T;
} ? [T?] : [];
type ActionByName<A extends Action, N extends string> = A extends unknown ? ActionName<A> extends N ? A : never : never;
type Depth = [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown];
type RulesPaths<D, Prefix extends string = '', N extends unknown[] = Depth> = N extends [unknown, ...infer Rest] ? D extends readonly Action[] ? `${Prefix}${ActionName<D[number]>}` : { [K in keyof D & string]: D[K] extends Definition ? RulesPaths<D[K], `${Prefix}${K}.`, Rest> : never }[keyof D & string] : never;
type SpecialSymbol = '~any' | '~all';
type SpecialPath<D, Prefix extends string = '', N extends unknown[] = Depth> = N extends [unknown, ...infer Rest] ? `${Prefix}${SpecialSymbol}` | (D extends readonly Action[] ? never : { [K in keyof D & string]: D[K] extends Definition ? SpecialPath<D[K], `${Prefix}${K}.`, Rest> : never }[keyof D & string]) : never;
type DataAtPath<D, P extends string, N extends unknown[] = Depth> = N extends [unknown, ...infer Rest] ? D extends readonly Action[] ? ActionArgs<ActionByName<D[number], P>> : P extends `${infer K}.${infer Tail}` ? K extends keyof D ? DataAtPath<D[K], Tail, Rest> : never : never : never;
type CheckerFn<D extends Definition> = <P extends RulesPaths<D>>(path: P, ...data: DataAtPath<D, P>) => boolean;
interface PermixHooks<D extends Definition = Definition> {
  setup: () => void;
  ready: () => void;
  check: (context: CheckContext<D>) => void;
}
interface Permix<D extends Definition> {
  /**
   * Provide the rules for this Permix instance. Must be called before `check()`.
   *
   * The rules object mirrors the shape of `D`: every leaf action becomes either
   * a `boolean` or a `(data) => boolean` validator.
   *
   * @example
   * ```ts
   * permix.setup({
   *   post: {
   *     create: true,
   *     edit: (post) => post.authorId === currentUserId,
   *   },
   * })
   * ```
   */
  setup: (rules: Rules<D>) => void;
  /**
   * Evaluate the current rules. Accepts one of three calling forms:
   *
   * - **Dot-path** — check a single action at a leaf path. Pass extra
   *   arguments after the path when the matched action declares `type`
   *   (required when `required: true`, optional otherwise).
   * - **Special token** — `'~any'` returns `true` if **any** rule in the tree
   *   (including dynamic ones called with no data) is truthy; `'~all'` returns
   *   `true` only if **every** rule is truthy. Prefix with a dot-path to scope
   *   the aggregation to a subtree, e.g. `'post.~all'` or
   *   `'workspace.customer.~any'`.
   * - **Callback** — compose multiple checks. `c` eagerly evaluates a rule and
   *   returns a plain boolean, so combine with `&&`, `||`, `!`, ternaries, or
   *   any custom logic.
   *
   * @example
   * ```ts
   * permix.check('post.create')
   * permix.check('post.edit', { authorId })
   * permix.check('~any')
   * permix.check('~all')
   * permix.check('post.~all')
   * permix.check('workspace.customer.~any')
   * permix.check(c => c('post.read') && c('post.edit'))
   * permix.check(c => !c('post.read'))
   * ```
   */
  check: (...args: CheckArgs<D>) => boolean;
  /**
   * Serialize the current rules into a JSON-safe object.
   *
   * Function-based rules are invoked once (with no check data) and their
   * boolean result is stored. Re-run `setup()` on the client if you need
   * dynamic rules that depend on check-time data.
   *
   * @example
   * ```ts
   * const state = permix.dehydrate()
   * // { post: { create: true, edit: false } }
   * ```
   */
  dehydrate: () => DehydratedState<D>;
  /**
   * Restore rules from a value produced by `dehydrate()`.
   *
   * Hydration restores only the serialized booleans and **does not** mark the
   * instance as ready: `isReady()` stays `false` and `isReadyAsync()` stays
   * pending until `setup()` is called. This is deliberate — dehydrated state
   * loses function-based rules, so you must re-run `setup()` on the client to
   * fully restore them. Gating on readiness surfaces a forgotten `setup()`
   * instead of silently serving collapsed permissions.
   *
   * @example
   * ```ts
   * permix.hydrate(serverState) // isReady() === false
   * permix.setup(clientRules)   // isReady() === true
   * ```
   */
  hydrate: (state: DehydratedState<D>) => void;
  /**
   * Define reusable permission rules separate from `setup()`.
   *
   * Static templates return a zero-arg function; dynamic templates accept
   * runtime parameters and return rules for `setup()`.
   *
   * @example
   * ```ts
   * const adminPermissions = permix.template({
   *   post: { create: true, read: true },
   * })
   * permix.setup(adminPermissions())
   * ```
   */
  template: <T = void>(rules: Rules<D> | ((param: T) => Rules<D>)) => (() => Rules<D>) | ((param: T) => Rules<D>);
  /**
   * Register a hook that fires every time the named event occurs.
   * Returns a function that removes the listener.
   *
   * @example
   * ```ts
   * const remove = permix.hook('setup', () => {
   *   console.log('Permissions were updated')
   * })
   * ```
   */
  hook: <K extends keyof PermixHooks<D>>(name: K, fn: PermixHooks<D>[K]) => () => void;
  /**
   * Register a hook that fires only once for the named event.
   *
   * @example
   * ```ts
   * permix.hookOnce('setup', () => {
   *   console.log('Permissions were updated once')
   * })
   * ```
   */
  hookOnce: <K extends keyof PermixHooks<D>>(name: K, fn: PermixHooks<D>[K]) => void;
  /**
   * Returns `true` if `setup()` has been called at least once (or initial
   * rules were passed to `createPermix`). `hydrate()` alone does **not** make
   * the instance ready.
   */
  isReady: () => boolean;
  /**
   * Returns a promise that resolves once the instance is ready — i.e. once
   * `setup()` has been called, or initial rules were provided. `hydrate()`
   * does **not** resolve it. Resolves immediately if already ready.
   *
   * @example
   * ```ts
   * await permix.isReadyAsync()
   * permix.check('post.create')
   * ```
   */
  isReadyAsync: () => Promise<void>;
  /**
   * Returns the current rules object.
   */
  getRules: () => Rules<D> | null;
  /**
   * Type-only carrier for the Permix definition schema. Use with `typeof` to
   * derive the definition without restating it. Always `undefined` at runtime.
   *
   * @example
   * ```ts
   * type Def = typeof permix.$inferDefinition
   * const other = createPermix<typeof permix.$inferDefinition>()
   * ```
   */
  readonly $inferDefinition: D;
  /**
   * Type-only carrier for the union of all valid permission paths
   * (e.g. `'user.create' | 'post.read'`). Use with `typeof` to derive
   * path types without repeating the definition. Always `undefined` at runtime.
   *
   * @example
   * ```ts
   * const path: typeof permix.$inferPath = 'user.create'
   *
   * const ALL = ['user.create', 'job.remove'] satisfies (typeof permix.$inferPath)[]
   * ```
   */
  readonly $inferPath: RulesPaths<D>;
}
/**
 * Create a type-safe Permix instance.
 *
 * @example Flat definition
 * ```ts
 * const permix = createPermix<['read', 'write']>()
 * permix.setup({ read: true, write: false })
 * permix.check('read') // true
 * ```
 *
 * @example Nested definition
 * ```ts
 * const permix = createPermix<{
 *   post: ['create', 'read']
 *   user: ['invite']
 * }>()
 * permix.setup({
 *   post: { create: true, read: true },
 *   user: { invite: false },
 * })
 * permix.check('post.create') // true
 * permix.check('user.invite') // false
 * ```
 *
 * @example Per-action data types
 * ```ts
 * const permix = createPermix<{
 *   post: [
 *     'create',
 *     'read',
 *     { name: 'edit', type: { authorId: string }, required: true },
 *   ]
 * }>()
 * permix.setup({
 *   post: {
 *     create: true,
 *     read: true,
 *     edit: post => post.authorId === me.id,
 *   },
 * })
 * permix.check('post.create')                // true
 * permix.check('post.edit', { authorId: '1' }) // true/false
 * ```
 */
declare function createPermix<D extends Definition>(initialRules?: Rules<D>): Permix<D>;
//#endregion
//#region src/core/check.d.ts
type CheckArgs<D extends Definition> = { [P in RulesPaths<D>]: [path: P, ...data: DataAtPath<D, P>] }[RulesPaths<D>] | [special: SpecialPath<D>] | [callback: (c: CheckerFn<D>) => boolean];
/**
 * Invoke a rule with no check data, treating a thrown error as `false`.
 *
 * `~any`/`~all` aggregation and `dehydrate()` evaluate every rule without an
 * entity. Entity-required validators (e.g. `post => post.authorId === id`)
 * throw on `undefined`, so we treat that as a denied permission instead of
 * letting the whole operation crash.
 */
declare function callRuleWithoutData(rule: () => unknown): boolean;
declare function createCheck<D extends Definition>(rules: Rules<D> | null | (() => Rules<D> | null)): (...args: CheckArgs<D>) => boolean;
interface CheckContext<D extends Definition> {
  path: RulesPaths<D> | SpecialPath<D> | null;
  data?: unknown;
}
declare function createCheckContext<D extends Definition>(...params: CheckArgs<D>): CheckContext<D>;
//#endregion
//#region src/core/errors.d.ts
declare class PermixError extends Error {
  constructor(message: string);
}
declare class PermixNotReadyError extends PermixError {
  constructor();
}
declare class PermixRuleNotDefinedError extends PermixError {
  path: string;
  constructor(path: string);
}
declare class PermixNotFoundError extends PermixError {
  key?: string | symbol;
  constructor(key?: string | symbol);
}
declare class PermixForbiddenError extends PermixError {
  constructor();
}
//#endregion
//#region src/core/hooks.d.ts
type HookFn = (...args: any[]) => void;
declare function createHooks<T extends { [K in keyof T]: HookFn } = Record<string, HookFn>>(): {
  hook: <K extends keyof T>(name: K, fn: T[K]) => (() => void);
  hookOnce: <K extends keyof T>(name: K, fn: T[K]) => void;
  removeHook: <K extends keyof T>(name: K, fn: T[K]) => void;
  callHook: <K extends keyof T>(name: K, ...args: Parameters<T[K]>) => void;
  clearHook: <K extends keyof T>(name: K) => void;
  clearAllHooks: () => void;
};
//#endregion
//#region src/core/merge.d.ts
type AsDefinition<T> = T extends Permix<infer D> ? D : T;
type Merge2<A, B> = A extends readonly Action[] ? B extends readonly Action[] ? readonly [...A, ...B] : B : B extends readonly Action[] ? B : { [K in keyof A | keyof B]: K extends keyof A ? K extends keyof B ? Merge2<A[K], B[K]> : A[K] : K extends keyof B ? B[K] : never };
type MergePermix<A, B> = Merge2<AsDefinition<A>, AsDefinition<B>>;
//#endregion
//#region src/core/template.d.ts
declare function createTemplate<D extends Definition, T = void>(rules: Rules<D> | ((param: T) => Rules<D>)): (param: T) => Rules<D>;
//#endregion
export { Definition as A, Rules as C, Action as D, hydrateRules as E, ActionName as O, DehydratedState as S, dehydrateRules as T, PermixHooks as _, PermixForbiddenError as a, SpecialSymbol as b, PermixRuleNotDefinedError as c, callRuleWithoutData as d, createCheck as f, Permix as g, DataAtPath as h, PermixError as i, ValidateDefinition as j, ActionSpec as k, CheckArgs as l, CheckerFn as m, MergePermix as n, PermixNotFoundError as o, createCheckContext as p, createHooks as r, PermixNotReadyError as s, createTemplate as t, CheckContext as u, RulesPaths as v, createRules as w, createPermix as x, SpecialPath as y };