import { type Kysely } from "kysely";
import type { VetraAccessCodesDB } from "./schema.js";
/** Per-user access window granted on redemption. */
export declare const ACCESS_DAYS = 30;
/** Max length accepted for an invite code. */
export declare const CODE_MAX_LENGTH = 100;
export type AccessStatus = {
    allowed: boolean;
    code?: string;
    label?: string;
    accessExpires?: string;
    /** True when the caller has an active redemption whose code carries a key. */
    hasAttachedKey: boolean;
};
export type InviteCodeView = {
    code: string;
    label: string | null;
    active: boolean;
    expiresAt: string | null;
    maxUses: number | null;
    createdAt: string;
    redemptions: number;
    /** Whether a Claude key is attached. The key value itself is never exposed. */
    hasAnthropicKey: boolean;
};
export type CreateCodeInput = {
    code: string;
    label?: string | null;
    expiresAt?: string | null;
    maxUses?: number | null;
    /** Pre-encrypted Anthropic key ciphertext, or null/undefined for none. */
    anthropicKeyCiphertext?: string | null;
};
export type RedemptionView = {
    code: string;
    userDid: string;
    redeemedAt: string;
    accessExpires: string | null;
};
export declare function normalizeCode(code: string): string;
/**
 * True when the code exists, is active, not past its expiry, and not at its
 * max_uses cap. Mirrors the checks redeemCode enforces, so a code that passes
 * here will actually be redeemable (no "validated then redeem fails" gap).
 */
export declare function isCodeUsable(db: Kysely<VetraAccessCodesDB>, code: string): Promise<boolean>;
/**
 * Redeem a code for a DID. Idempotent: a DID re-redeeming the same code is a
 * no-op success. Enforces `max_uses` (distinct redeeming DIDs) when set.
 */
export declare function redeemCode(db: Kysely<VetraAccessCodesDB>, code: string, did: string): Promise<{
    ok: boolean;
}>;
/** Most recent non-expired redemption for a DID, with its cohort label. */
export declare function getAccessStatus(db: Kysely<VetraAccessCodesDB>, did: string): Promise<AccessStatus>;
/**
 * True when the DID has at least one active (non-expired) redemption whose
 * code carries an attached key. Mirrors the selection in
 * getRedeemedKeyCiphertext so the UI's `hasAttachedKey` and the actual
 * injection agree.
 */
export declare function hasAttachedKeyForDid(db: Kysely<VetraAccessCodesDB>, did: string): Promise<boolean>;
/**
 * The encrypted attached key for the DID's most-recent active redemption whose
 * code carries one, or null if there is none. "Active" means the redemption's
 * access window has not expired.
 */
export declare function getRedeemedKeyCiphertext(db: Kysely<VetraAccessCodesDB>, did: string): Promise<string | null>;
/** All codes with their redemption counts, newest first (admin listing). */
export declare function listCodes(db: Kysely<VetraAccessCodesDB>): Promise<InviteCodeView[]>;
export type RedemptionFilter = {
    code?: string | null;
    /** Wallet address (0x…), matched against the DID suffix on any chain. */
    address?: string | null;
};
/**
 * Redemptions, newest first. Optionally filtered by code and/or by the
 * redeeming wallet address. With no filter, every redemption (audit). Admin use.
 */
export declare function listRedemptions(db: Kysely<VetraAccessCodesDB>, filter?: RedemptionFilter): Promise<RedemptionView[]>;
/**
 * Revoke a wallet's currently-valid access by expiring its redemptions
 * (access_expires set to now). Keeps the audit rows. Returns how many
 * still-valid grants were revoked.
 *
 * Note: this does not bar re-acquiring access. Re-redeeming the *same* code
 * is a no-op (the redemption already exists, so the expired window stays),
 * but redeeming a *different* still-active code grants fresh access — disable
 * the relevant codes too for a hard lockout.
 */
export declare function revokeAccess(db: Kysely<VetraAccessCodesDB>, address: string): Promise<number>;
/** Create a code (idempotent on the code string). Returns the resulting row. */
export declare function createCode(db: Kysely<VetraAccessCodesDB>, input: CreateCodeInput): Promise<InviteCodeView>;
/**
 * Set or clear a code's attached key. Pass the pre-encrypted ciphertext to set
 * it, or null to detach. Returns the updated view, or null if the code is
 * missing.
 */
export declare function setCodeAnthropicKey(db: Kysely<VetraAccessCodesDB>, code: string, ciphertext: string | null): Promise<InviteCodeView | null>;
/** Toggle a code's active flag. Returns the updated row, or null if missing. */
export declare function setActiveCode(db: Kysely<VetraAccessCodesDB>, code: string, active: boolean): Promise<InviteCodeView | null>;
//# sourceMappingURL=codes.d.ts.map