import { IFieldDiffer, DiffResult } from './integration-field-diff.protocol.js';
import 'zod';

interface DeepEqualDifferOptions {
    /**
     * Extra field names to ignore in addition to the defaults. Consumers can
     * pass `['integration_version']` etc. to augment the base list; values here are
     * merged (not replaced) with `DEFAULT_IGNORE_FIELDS`.
     */
    readonly ignore?: readonly string[];
    /**
     * Field names to REMOVE from the default ignore list — the inverse of
     * `ignore`. Use this to declare that a normally-metadata column is in fact
     * DOMAIN DATA for this entity and must register as a field change.
     *
     * The canonical case (swe-brain ADR-0008 §1, the gap this knob closes):
     * `deletedAt` is in `DEFAULT_IGNORE_FIELDS` because most sinks stamp it as
     * row metadata sinks own unconditionally. But an entity with
     * `softDelete: false` and a domain-owned `deleted_at` carries the
     * vendor-observed retraction tombstone ON the canonical record (a Slack
     * `message_deleted` → `deletedAt`). Without un-ignoring it, the tombstone
     * overlay diffs to `'noop'`, the upsert is skipped, and `deleted_at` never
     * lands. `unignore: ['deletedAt']` makes the differ treat it as domain data.
     *
     * Applied AFTER `ignore` is merged, so `unignore` wins on a field listed in
     * both. Subtracting a field not in the (merged) ignore set is a harmless
     * no-op. Does not touch `DEFAULT_IGNORE_FIELDS` for any other instance.
     */
    readonly unignore?: readonly string[];
}
declare class DeepEqualDiffer<T extends Record<string, unknown>> implements IFieldDiffer<T> {
    private readonly ignore;
    constructor(opts?: DeepEqualDifferOptions);
    diff(existing: T | null, incoming: T, providerChangedFields?: string[]): DiffResult;
}

export { DeepEqualDiffer, type DeepEqualDifferOptions };
