/**
 * MeshRpc — the signed, recipient-bound machine-to-machine command layer for the
 * Multi-Machine Session Pool (spec §L0). A thin request/response envelope over the
 * existing authenticated HTTP/tunnel channel carrying a small command set:
 * place / claim / release / transfer / capacity-report / session-status /
 * secret-share.
 *
 * This module is PURE LOGIC — the canonical envelope, the 5-step receipt
 * verification, and the per-command RBAC gate. Crypto (Ed25519 sign/verify), the
 * nonce store, the peer registry, and the router/ownership reads are injected as
 * seams so the dangerous parts (recipient-binding, replay, authorization) are
 * unit-testable with in-memory fakes. The HTTP transport + production wiring sit
 * on top and call these functions.
 *
 * Two independent gates protect every command (spec §L0 Invariant):
 *   (a) verifyEnvelope — WHO sent it: a valid Ed25519 signature from a registered
 *       peer of the same agent, cryptographically bound to THIS recipient, fresh
 *       (unseen nonce) and timely (timestamp within tolerance).
 *   (b) checkCommandRBAC — whether they MAY issue it: the per-command role check
 *       (place/transfer → router; claim → placement-target or failover-router;
 *       release → owner or failover-router; reports/secret-share → any peer).
 * The CAS (§L3) is the final correctness fence; these gates refuse an
 * unauthorized command at the door, before any state read/write.
 */
export type MachineId = string;
export type MeshCommand = {
    type: 'place';
    session: string;
    machine: MachineId;
} | {
    type: 'claim';
    session: string;
    epoch: number;
    failover?: boolean;
} | {
    type: 'release';
    session: string;
    epoch: number;
    failover?: boolean;
} | {
    type: 'transfer';
    session: string;
    target: MachineId;
} | {
    type: 'deliverMessage';
    session: string;
    messageId: string;
    payload: unknown;
    ownershipEpoch: number;
} | {
    type: 'drain';
    session: string;
    target: MachineId;
    ownershipEpoch: number;
} | {
    type: 'capacity-report';
} | {
    type: 'session-status';
    session?: string;
} | {
    type: 'secret-share';
    encrypted: string;
} | {
    type: 'slice-renew';
    mandateId: string;
    accountId: string;
    requestingMachineFp: string;
    amount: number;
    expiresAt: number;
} | {
    type: 'account-follow-me-mandate-deliver';
    /** The R4a-signed bundle: the mandate + its asymmetric issuance signature. */
    portable: import('../coordination/AccountFollowMeMandateBridge.js').PortableMandate;
} | {
    type: 'pool-stream-ticket';
    session: string;
} | {
    type: 'journal-sync';
    advert?: Record<string, Record<string, {
        incarnation: string;
        lastSeq: number;
    }>>;
    request?: {
        machineId: string;
        kind: string;
        fromSeq: number;
    };
    batch?: {
        kind: string;
        incarnation: string;
        entries: unknown[];
        oldestRetainedSeq?: number;
    }[];
} | {
    type: 'commitments-sync';
    request: {
        sinceSeq: number;
        incarnation?: string;
    };
} | {
    type: 'state-snapshot';
    request: {
        store: string;
    };
} | {
    type: 'preferences-sync';
    request: {
        sinceSeq: number;
        incarnation?: string;
    };
} | {
    type: 'commitment-mutate';
    payload: {
        origin: string;
        id: string;
        op: 'deliver' | 'withdraw' | 'resume' | 'patch-beacon' | 'probe' | 'transition';
        args?: Record<string, unknown>;
        opKey: string;
        requestedAt: string;
        callerMachineId: string;
        observedStatus?: string;
    };
} | {
    type: 'topic-profile-pull';
    topics: string[];
} | {
    type: 'working-set-pull';
    topic: number;
    manifestOnly?: boolean;
    want?: {
        relPath: string;
        offset: number;
    }[];
} | {
    type: 'pool-view-fetch';
    viewId: string;
    method: string;
    probeOnly?: boolean;
    assertion?: unknown;
};
export interface MeshEnvelope {
    sender: MachineId;
    recipient: MachineId;
    command: MeshCommand;
    epoch: number;
    nonce: string;
    timestamp: number;
    signature: string;
}
/** The canonical bytes the signature covers — field-ordered, recipient included. */
export declare function canonicalizeEnvelope(e: Pick<MeshEnvelope, 'sender' | 'recipient' | 'command' | 'epoch' | 'nonce' | 'timestamp'>): string;
/** Build + sign an outgoing command envelope naming THIS sender + the recipient. */
export declare function signEnvelope(parts: {
    sender: MachineId;
    recipient: MachineId;
    command: MeshCommand;
    epoch: number;
    nonce: string;
    timestamp: number;
}, sign: (canonical: string) => string): MeshEnvelope;
export type VerifyReason = 'ok' | 'wrong-recipient' | 'signature-invalid' | 'unknown-sender' | 'replayed-nonce' | 'stale-timestamp';
export interface VerifyEnvelopeDeps {
    /** This machine's id — the envelope's `recipient` MUST equal it. */
    selfMachineId: MachineId;
    /** Verify the Ed25519 signature over `canonical` against `sender`'s REGISTERED key. */
    verify: (canonical: string, signature: string, sender: MachineId) => boolean;
    /** Is `sender` a registered peer machine of THIS agent? */
    isRegisteredPeer: (sender: MachineId) => boolean;
    /** Has this nonce been seen for `sender` (replay guard, NonceStore-backed)? */
    seenNonce: (sender: MachineId, nonce: string) => boolean;
    /** Wall clock (injectable). */
    now: () => number;
    /** Max |now - timestamp| (ms). Default 30000. */
    clockToleranceMs?: number;
}
/**
 * The 5-step receipt verification (spec §L0), evaluated IN ORDER. Pure: it does
 * NOT record the nonce — the caller records it ONLY on a fully-accepted command
 * (after RBAC), so a rejected command never burns a nonce.
 */
export declare function verifyEnvelope(env: MeshEnvelope, deps: VerifyEnvelopeDeps): {
    ok: boolean;
    reason: VerifyReason;
};
export type RbacReason = 'ok' | 'not-router' | 'claim-unauthorized' | 'release-unauthorized' | 'drain-unauthorized' | 'slice-renew-unauthorized' | 'mandate-deliver-unauthorized';
export interface RbacDeps {
    /** The machine currently holding the router lease (verify-on-read, §L1), or null. */
    routerHolder: () => MachineId | null;
    /** The current owner machine of a session, or null. */
    ownerOf: (session: string) => MachineId | null;
    /** The machine the router last assigned (via place/transfer) for a session, or null. */
    placementTargetOf: (session: string) => MachineId | null;
    /**
     * WS5.2 R7a — the operator-mandate gate for the `slice-renew` verb. Returns true ONLY when the
     * authorizing mandate authorizes (sender, accountId, requesting fingerprint) for account follow-me
     * — deny-by-default. INJECTED so the dangerous authority decision is a real check, never an
     * inherit. ABSENT ⇒ the verb is refused (fail-closed): on a build without the seam wired, a
     * slice-renew can never be authorized. Mirrors the deny-by-default discipline of R3a/R4a.
     */
    authorizeSliceRenew?: (args: {
        sender: MachineId;
        mandateId: string;
        accountId: string;
        requestingMachineFp: string;
    }) => boolean;
    /**
     * WS5.2 R4a — the gate for `account-follow-me-mandate-deliver`. Returns true ONLY when account
     * follow-me is ENABLED on this machine AND the sender is THIS machine's trusted operator machine
     * (the verified-operator binding). Deny-by-default: ABSENT ⇒ the verb is refused (fail-closed) —
     * on a build without the seam wired, or on a non-dev/dark agent, a delivered mandate can never be
     * accepted at the gate. This is ONLY the coarse "should I even look at it" gate; the LOAD-BEARING
     * authority is the R4a asymmetric signature verification in the handler, which re-binds to the
     * authenticated sender + registered operator key. Mirrors the deny-by-default discipline of R3a.
     */
    authorizeMandateDeliver?: (args: {
        sender: MachineId;
    }) => boolean;
}
/**
 * Per-command authorization gate (spec §L0). A valid signature proves WHO; this
 * proves they MAY. Runs BEFORE any state read/write. `sender` is the verified
 * envelope sender; `command` is its command.
 */
export declare function checkCommandRBAC(command: MeshCommand, sender: MachineId, deps: RbacDeps): {
    ok: boolean;
    reason: RbacReason;
};
/**
 * Full acceptance gate: verify (who) THEN RBAC (may). Returns the first failure's
 * reason. The caller records the nonce ONLY when this returns ok (so a rejected
 * command never consumes a nonce). Convenience over verifyEnvelope + checkCommandRBAC.
 */
export declare function acceptEnvelope(env: MeshEnvelope, verifyDeps: VerifyEnvelopeDeps, rbacDeps: RbacDeps): {
    ok: boolean;
    reason: VerifyReason | RbacReason;
};
/** A handler for one command type. Receives the (already-authorized) command, the
 *  verified sender, and the full envelope (for nonce/epoch/timestamp, e.g. the
 *  per-session ownership CAS uses `env.nonce`). */
export type MeshCommandHandler = (command: MeshCommand, sender: MachineId, env: MeshEnvelope) => Promise<unknown> | unknown;
export interface MeshRpcDispatcherDeps {
    verify: VerifyEnvelopeDeps;
    rbac: RbacDeps;
    /** Record a nonce as seen (NonceStore-backed) — called ONLY on full accept. */
    recordNonce: (sender: MachineId, nonce: string) => void;
    /** Per-command handlers. A missing handler → `no-handler` (the command is verified+authorized but unimplemented on this layer). */
    handlers: Partial<Record<MeshCommand['type'], MeshCommandHandler>>;
    /** Audit sink for rejections (SecurityLog). Optional. */
    onReject?: (env: MeshEnvelope, reason: string) => void;
    logger?: (msg: string) => void;
}
export type DispatchResult = {
    ok: true;
    result: unknown;
} | {
    ok: false;
    reason: VerifyReason | RbacReason | 'no-handler';
    status: number;
};
/**
 * The receive side of MeshRpc — transport-agnostic (the HTTP route, or a tunnel
 * carrier, calls `dispatch(envelope)`). Runs the two gates (verify THEN rbac),
 * records the nonce ONLY on full accept (a rejected command never burns a nonce),
 * audits rejections, then routes to the registered handler. Returns a result +
 * an HTTP status so any transport can map it.
 */
export declare class MeshRpcDispatcher {
    private readonly d;
    constructor(deps: MeshRpcDispatcherDeps);
    dispatch(env: MeshEnvelope): Promise<DispatchResult>;
}
//# sourceMappingURL=MeshRpc.d.ts.map