/**
 * LegalHoldStore -- P4-RET-03 Legal Hold Mechanism
 *
 * In-memory Map-based implementation for this cycle.
 * Prisma-backed persistence is a follow-up (migration flagged below).
 *
 * Core contract:
 *   - create()  -- validates scope, routes to approval queue, returns
 *                  a 'pending' hold that does NOT match deletion queries.
 *   - extend()  -- updates expiresAt after a fresh approval.
 *   - release() -- marks 'released' after a fresh approval. Does NOT
 *                  auto-delete previously held data (AC 10).
 *   - findHoldsMatching() -- deletion-engine query: returns active holds
 *                  whose scope covers the given record.
 *   - list()    -- partner-admin / legal-reviewer query.
 *
 * Approval-queue hook:
 *   create() and release() route through the provided ApprovalQueueHook
 *   before committing status changes. The hook is intentionally thin: it
 *   enqueues an entry and returns a promise that resolves when the entry
 *   is resolved (approved/denied). This decouples LegalHoldStore from the
 *   governance-server's full ApprovalQueue implementation so it can be
 *   used in the core SDK without dragging in HTTP server dependencies.
 *
 * Spec: P4-RET-01 Section 2.3, AC 7-10
 *
 * @connexum/ai-governance
 */
import type { LegalHold, LegalHoldScope, ISO8601, AuditChainRef } from './legal-hold';
/**
 * Minimal interface the LegalHoldStore needs from the approval queue.
 * The governance-server passes a real implementation; tests pass a stub.
 *
 * The store calls enqueue() and waits for the returned promise. If the
 * reviewer denies the request, enqueue() should reject with an Error.
 * The store surfaces that rejection to the caller as-is.
 */
export interface ApprovalQueueHook {
    /**
     * Enqueue a legal-reviewer approval request.
     *
     * @param subject   Human-readable description (e.g. "Create legal hold for tenant X").
     * @param holdId    The hold being acted on.
     * @param actor     Who is requesting the action.
     * @param action    'create' | 'extend' | 'release'
     * @returns         Promise that resolves with the approval-queue entry ID
     *                  once the request is approved, or rejects if denied.
     */
    enqueue(subject: string, holdId: string, actor: string, action: 'create' | 'extend' | 'release'): Promise<string>;
}
/**
 * Descriptor for the record being checked against active legal holds.
 * All fields are optional; the store uses whichever fields are present.
 */
export interface RecordDescriptor {
    tenantId?: string;
    contractId?: string;
    agentId?: string;
    packBinding?: string[];
    /** ISO-8601 timestamp of the record (used for dateRange scope filter). */
    timestamp?: ISO8601;
    /** Optional case tag on the record (matched against scope.caseTag). */
    caseTag?: string;
}
export interface LegalHoldListFilter {
    tenantId?: string;
    contractId?: string;
    agentId?: string;
    caseTag?: string;
    packId?: string;
    status?: 'pending' | 'active' | 'released';
}
export interface CreateLegalHoldInput {
    scope: LegalHoldScope;
    reason: string;
    expiresAt?: ISO8601;
}
export interface ExtendLegalHoldInput {
    newExpiresAt: ISO8601;
}
/**
 * The store calls this after every lifecycle transition so the
 * governance-server can append to the tamper-evident audit chain.
 * Returns the chain entry ID that gets recorded in chainOfCustody.
 */
export type AuditEmitter = (eventName: string, holdId: string, actor: string, metadata: Record<string, unknown>) => Promise<AuditChainRef>;
export declare function makeNoOpAuditEmitter(): AuditEmitter;
/**
 * Stores, retrieves, and queries LegalHold entities.
 *
 * Thread-safety note: Node.js is single-threaded; the Map operations
 * here are effectively atomic. The ConcurrencyError guard exists for
 * the logical race (pending -> release without active transition) not
 * for actual memory races.
 */
export declare class LegalHoldStore {
    private readonly holds;
    private readonly approvalQueue;
    private readonly emitAudit;
    constructor(approvalQueue: ApprovalQueueHook, emitAudit?: AuditEmitter);
    /**
     * Create a new LegalHold.
     *
     * The hold starts in 'pending' status and does NOT match deletion queries
     * until a legal-reviewer approves it. Approval is handled via the
     * ApprovalQueueHook provided at construction time.
     *
     * Throws LegalHoldScopeEmptyError if the scope has no populated fields.
     *
     * @param input  Creation parameters (scope, reason, optional expiresAt).
     * @param actor  Authenticated actor submitting the request (JWT sub claim).
     * @returns      The hold in 'pending' status after enqueuing approval.
     *               The returned hold becomes 'active' asynchronously once
     *               a legal-reviewer approves it. Callers should poll or
     *               subscribe to audit events for the transition.
     */
    create(input: CreateLegalHoldInput, actor: string): Promise<LegalHold>;
    /**
     * Extend the expiry of an active LegalHold.
     *
     * Requires a fresh legal-reviewer approval (same queue, new entry).
     * Only 'active' holds can be extended; pending holds must first become
     * active. Released holds cannot be extended.
     *
     * @param holdId      The hold to extend.
     * @param newExpires  New expiry ISO-8601 timestamp.
     * @param actor       Authenticated actor requesting the extension.
     */
    extend(holdId: string, newExpires: ISO8601, actor: string): Promise<LegalHold>;
    /**
     * Release a LegalHold.
     *
     * Only 'active' holds can be released. A 'pending' hold cannot be
     * released directly -- that would be a concurrency / logic bypass.
     * Throwing LegalHoldConcurrencyError on the pending->released path
     * covers the PT-RET-2 race scenario.
     *
     * Release does NOT auto-delete previously held data (AC 10). Records
     * past their retention window at release time are flagged by the next
     * scheduled job.
     *
     * @param holdId  The hold to release.
     * @param actor   Authenticated actor requesting the release.
     */
    release(holdId: string, actor: string): Promise<LegalHold>;
    /**
     * Deletion-engine query.
     *
     * Returns all ACTIVE holds whose scope matches the given record.
     * Pending and released holds are excluded (only 'active' blocks deletion).
     *
     * The tenant-scope is authoritative: a hold with tenantId='acme' catches
     * every record where record.tenantId === 'acme', regardless of whether
     * the hold also has a narrower agentId or packId constraint.
     *
     * @param record  Descriptor of the record being considered for deletion.
     * @returns       Array of active LegalHold objects that cover the record.
     *                Empty array means the record is not held and deletion may proceed.
     */
    findHoldsMatching(record: RecordDescriptor): Promise<LegalHold[]>;
    /**
     * Partner-admin / legal-reviewer query.
     *
     * Returns holds matching the given filter criteria (all fields are
     * optional AND-combined). Returns all holds when no filter is supplied.
     *
     * @param filter  Optional filter criteria.
     * @returns       Matching holds, ordered by createdAt descending.
     */
    list(filter?: LegalHoldListFilter): Promise<LegalHold[]>;
    /**
     * Activate a pending hold after approval.
     * Used by routes that implement asynchronous approval resolution
     * (e.g. a human clicks Approve in the dashboard after the initial
     * POST /legal-holds request returned a 202).
     *
     * Emits the 'retention:legal-hold-created' audit event at activation
     * time (not at enqueue time) so the chain reflects actual approval.
     */
    activatePending(holdId: string, approvalEntryId: string, actor: string): Promise<LegalHold>;
    /**
     * Get a single hold by ID. Returns undefined if not found.
     * Used by routes for GET single-item endpoints.
     */
    get(holdId: string): LegalHold | undefined;
    /**
     * Internal size accessor (used in tests).
     */
    get size(): number;
}
//# sourceMappingURL=legal-hold-store.d.ts.map