import { EventEmitter } from 'tseep';
import debug$1 from 'debug';
import { LRUCache } from 'typescript-lru-cache';
import { nip19 } from 'nostr-tools';
import { EventEmitter as EventEmitter$1 } from 'node:events';

declare enum NDKKind {
    Metadata = 0,
    Text = 1,
    RecommendRelay = 2,
    Contacts = 3,
    EncryptedDirectMessage = 4,
    EventDeletion = 5,
    Repost = 6,
    Reaction = 7,
    BadgeAward = 8,
    GroupChat = 9,
    Thread = 11,
    GroupReply = 12,
    GiftWrapSeal = 13,
    PrivateDirectMessage = 14,
    Image = 20,
    Video = 21,
    ShortVideo = 22,
    Story = 23,
    Vanish = 62,
    CashuWalletBackup = 375,
    GiftWrap = 1059,
    GenericRepost = 16,
    ChannelCreation = 40,
    ChannelMetadata = 41,
    ChannelMessage = 42,
    ChannelHideMessage = 43,
    ChannelMuteUser = 44,
    WikiMergeRequest = 818,
    GenericReply = 1111,
    Media = 1063,
    VoiceMessage = 1222,
    VoiceReply = 1244,
    DraftCheckpoint = 1234,
    Task = 1934,
    Report = 1984,
    Label = 1985,
    DVMReqTextExtraction = 5000,
    DVMReqTextSummarization = 5001,
    DVMReqTextTranslation = 5002,
    DVMReqTextGeneration = 5050,
    DVMReqImageGeneration = 5100,
    DVMReqTextToSpeech = 5250,
    DVMReqDiscoveryNostrContent = 5300,
    DVMReqDiscoveryNostrPeople = 5301,
    DVMReqTimestamping = 5900,
    DVMEventSchedule = 5905,
    DVMJobFeedback = 7000,
    Subscribe = 7001,
    Unsubscribe = 7002,
    SubscriptionReceipt = 7003,
    CashuReserve = 7373,
    CashuQuote = 7374,
    CashuToken = 7375,
    CashuWalletTx = 7376,
    GroupAdminAddUser = 9000,
    GroupAdminRemoveUser = 9001,
    GroupAdminEditMetadata = 9002,
    GroupAdminEditStatus = 9006,
    GroupAdminCreateGroup = 9007,
    GroupAdminRequestJoin = 9021,
    MuteList = 10000,
    PinList = 10001,
    RelayList = 10002,
    BookmarkList = 10003,
    CommunityList = 10004,
    PublicChatList = 10005,
    BlockRelayList = 10006,
    SearchRelayList = 10007,
    SimpleGroupList = 10009,
    RelayFeedList = 10012,
    InterestList = 10015,
    CashuMintList = 10019,
    EmojiList = 10030,
    DirectMessageReceiveRelayList = 10050,
    BlossomList = 10063,
    NostrWaletConnectInfo = 13194,
    TierList = 17000,
    CashuWallet = 17375,
    FollowSet = 30000,
    CategorizedPeopleList = 30000,// Deprecated but left for backwards compatibility
    CategorizedBookmarkList = 30001,// Deprecated but left for backwards compatibility
    RelaySet = 30002,
    CategorizedRelayList = 30002,// Deprecated but left for backwards compatibility
    BookmarkSet = 30003,
    /**
     * @deprecated Use ArticleCurationSet instead
     */
    CurationSet = 30004,// Deprecated but left for backwards compatibility
    ArticleCurationSet = 30004,
    VideoCurationSet = 30005,
    ImageCurationSet = 30006,
    InterestSet = 30015,
    InterestsList = 30015,// Deprecated but left for backwards compatibility
    ProjectTemplate = 30717,
    EmojiSet = 30030,
    ModularArticle = 30040,
    ModularArticleItem = 30041,
    Wiki = 30818,
    Draft = 31234,
    Project = 31933,
    SubscriptionTier = 37001,
    EcashMintRecommendation = 38000,
    CashuMintAnnouncement = 38172,
    FedimintMintAnnouncement = 38173,
    P2POrder = 38383,
    CollaborativeEvent = 39382,
    HighlightSet = 39802,
    CategorizedHighlightList = 39802,// Deprecated but left for backwards compatibility
    Nutzap = 9321,
    ZapRequest = 9734,
    Zap = 9735,
    Highlight = 9802,
    ClientAuth = 22242,
    NostrWalletConnectReq = 23194,
    NostrWalletConnectRes = 23195,
    NostrConnect = 24133,
    BlossomUpload = 24242,
    HttpAuth = 27235,
    ProfileBadge = 30008,
    BadgeDefinition = 30009,
    MarketStall = 30017,
    MarketProduct = 30018,
    Article = 30023,
    AppSpecificData = 30078,
    Classified = 30402,
    HorizontalVideo = 34235,
    VerticalVideo = 34236,
    GroupMetadata = 39000,// NIP-29
    GroupAdmins = 39001,// NIP-29
    GroupMembers = 39002,// NIP-29
    FollowPack = 39089,
    MediaFollowPack = 39092,
    AppRecommendation = 31989,
    AppHandler = 31990
}

/**
 * Represents an HLL (HyperLogLog) data structure for cardinality estimation.
 * Contains 256 uint8 registers as specified in NIP-45.
 */
declare class NDKCountHll {
    /**
     * The 256 uint8 registers used for HLL estimation
     */
    readonly registers: Uint8Array;
    constructor(registers?: Uint8Array);
    /**
     * Creates an NDKCountHll from a hex-encoded string (512 characters).
     * Each register is a uint8 value encoded as 2 hex characters.
     *
     * @param hex - The hex string (512 characters = 256 bytes)
     * @returns A new NDKCountHll instance
     * @throws Error if the hex string is invalid
     */
    static fromHex(hex: string): NDKCountHll;
    /**
     * Converts the HLL registers to a hex-encoded string.
     *
     * @returns The hex string representation (512 characters)
     */
    toHex(): string;
    /**
     * Merges this HLL with another HLL by taking the maximum value for each register.
     * This is the standard HLL merge operation that allows combining counts
     * from multiple relays without double-counting.
     *
     * @param other - The other HLL to merge with
     * @returns A new NDKCountHll with the merged registers
     */
    merge(other: NDKCountHll): NDKCountHll;
    /**
     * Merges multiple HLLs by taking the maximum value for each register.
     *
     * @param hlls - Array of HLLs to merge
     * @returns A new NDKCountHll with the merged registers
     */
    static merge(hlls: NDKCountHll[]): NDKCountHll;
    /**
     * Estimates the cardinality (unique count) using the HyperLogLog algorithm.
     *
     * Uses the standard HLL formula with bias correction for small and large cardinalities.
     *
     * @returns The estimated unique count
     */
    estimate(): number;
    /**
     * Checks if this HLL is empty (all registers are zero).
     *
     * @returns True if all registers are zero
     */
    isEmpty(): boolean;
    /**
     * Creates a copy of this HLL.
     *
     * @returns A new NDKCountHll with the same register values
     */
    clone(): NDKCountHll;
}
/**
 * Result of a COUNT request, including optional HLL data.
 */
interface NDKCountResult {
    /**
     * The count value returned by the relay.
     * This is the exact count if HLL is not available,
     * or an approximate count if HLL is used.
     */
    count: number;
    /**
     * The HLL data if returned by the relay.
     * Can be used to merge counts from multiple relays.
     */
    hll?: NDKCountHll;
}
/**
 * Aggregated result from multiple relays for a COUNT request.
 */
interface NDKAggregatedCountResult {
    /**
     * The best estimate of the count.
     * If HLL data is available from multiple relays, this is computed from the merged HLL.
     * Otherwise, it's the maximum count from all relays.
     */
    count: number;
    /**
     * The merged HLL from all relays that returned HLL data.
     * Can be used for further aggregation or analysis.
     */
    mergedHll?: NDKCountHll;
    /**
     * Individual results from each relay.
     */
    relayResults: Map<string, NDKCountResult>;
}
/**
 * Options for count requests.
 */
interface NDKCountOptions {
    /**
     * Custom ID for the count request.
     */
    id?: string;
    /**
     * Timeout in milliseconds for the count request.
     * @default 5000
     */
    timeout?: number;
}

/**
 * NDKUserProfile represents a user's kind 0 profile metadata
 */
interface NDKUserProfile {
    [key: string]: string | number | undefined;
    created_at?: number;
    name?: string;
    displayName?: string;
    /**
     * @deprecated Use picture instead
     */
    image?: string;
    picture?: string;
    banner?: string;
    bio?: string;
    nip05?: string;
    lud06?: string;
    lud16?: string;
    about?: string;
    website?: string;
    profileEvent?: string;
}

type Hexpubkey = string;
type Npub = string;
type ProfilePointer = {
    pubkey: string;
    relays?: string[];
    nip46?: string[];
};
interface NDKUserParams {
    npub?: Npub;
    hexpubkey?: Hexpubkey;
    pubkey?: Hexpubkey;
    nip05?: string;
    relayUrls?: string[];
    nip46Urls?: string[];
    nprofile?: string;
}
/**
 * Represents a pubkey.
 */
declare class NDKUser {
    ndk: NDK | undefined;
    profile?: NDKUserProfile;
    profileEvent?: NDKEvent;
    private _npub?;
    private _pubkey?;
    relayUrls: string[];
    readonly nip46Urls: string[];
    constructor(opts: NDKUserParams);
    get npub(): string;
    get nprofile(): string;
    set npub(npub: Npub);
    /**
     * Get the user's pubkey
     * @returns {string} The user's pubkey
     */
    get pubkey(): string;
    /**
     * Set the user's pubkey
     * @param pubkey {string} The user's pubkey
     */
    set pubkey(pubkey: string);
    /**
     * Equivalent to NDKEvent.filters().
     * @returns {NDKFilter}
     */
    filter(): NDKFilter;
    /**
     * Gets NIP-57 and NIP-61 information that this user has signaled
     *
     * @param getAll {boolean} Whether to get all zap info or just the first one
     */
    getZapInfo(timeoutMs?: number): Promise<Map<NDKZapMethod, NDKZapMethodInfo>>;
    /**
     * Instantiate an NDKUser from a NIP-05 string
     * @param nip05Id {string} The user's NIP-05
     * @param ndk {NDK} An NDK instance
     * @param skipCache {boolean} Whether to skip the cache or not
     * @returns {NDKUser | undefined} An NDKUser if one is found for the given NIP-05, undefined otherwise.
     */
    static fromNip05(nip05Id: string, ndk: NDK, skipCache?: boolean): Promise<NDKUser | undefined>;
    /**
     * Fetch a user's profile
     * @param opts {NDKSubscriptionOptions} A set of NDKSubscriptionOptions
     * @param storeProfileEvent {boolean} Whether to store the profile event or not
     * @returns User Profile
     */
    fetchProfile(opts?: NDKSubscriptionOptions, storeProfileEvent?: boolean): Promise<NDKUserProfile | null>;
    /**
     * Returns a set of users that this user follows.
     *
     * @deprecated Use followSet instead
     */
    follows: (opts?: NDKSubscriptionOptions | undefined, outbox?: boolean | undefined, kind?: number | undefined) => Promise<Set<NDKUser>>;
    /**
     * Returns a set of pubkeys that this user follows.
     *
     * @param opts - NDKSubscriptionOptions
     * @param outbox - boolean
     * @param kind - number
     */
    followSet(opts?: NDKSubscriptionOptions, outbox?: boolean, kind?: number): Promise<Set<Hexpubkey>>;
    /** @deprecated Use referenceTags instead. */
    /**
     * Get the tag that can be used to reference this user in an event
     * @returns {NDKTag} an NDKTag
     */
    tagReference(): NDKTag;
    /**
     * Get the tags that can be used to reference this user in an event
     * @returns {NDKTag[]} an array of NDKTag
     */
    referenceTags(marker?: string): NDKTag[];
    /**
     * Publishes the current profile.
     */
    publish(): Promise<void>;
    /**
     * Add one or more follows to this user's contact list
     *
     * @param newFollow {NDKUser | Hexpubkey | Array} The user(s) to follow
     * @param currentFollowList {Set<NDKUser | Hexpubkey>} The current follow list
     * @param kind {NDKKind} The kind to use for this contact list (defaults to `3`)
     * @returns {Promise<boolean>} True if any follows were added, false if all already exist
     */
    follow(newFollow: NDKUser | Hexpubkey | (NDKUser | Hexpubkey)[], currentFollowList?: Set<NDKUser | Hexpubkey>, kind?: NDKKind): Promise<boolean>;
    /**
     * Remove one or more follows from this user's contact list
     *
     * @param user {NDKUser | Hexpubkey | Array} The user(s) to unfollow
     * @param currentFollowList {Set<NDKUser | Hexpubkey>} The current follow list
     * @param kind {NDKKind} The kind to use for this contact list (defaults to `3`)
     * @returns The relays where the follow list was published or false if none were found
     */
    unfollow(user: NDKUser | Hexpubkey | (NDKUser | Hexpubkey)[], currentFollowList?: Set<NDKUser | Hexpubkey>, kind?: NDKKind): Promise<Set<NDKRelay> | boolean>;
    /**
     * Validate a user's NIP-05 identifier (usually fetched from their kind:0 profile data)
     *
     * @param nip05Id The NIP-05 string to validate
     * @returns {Promise<boolean | null>} True if the NIP-05 is found and matches this user's pubkey,
     * False if the NIP-05 is found but doesn't match this user's pubkey,
     * null if the NIP-05 isn't found on the domain or we're unable to verify (because of network issues, etc.)
     */
    validateNip05(nip05Id: string): Promise<boolean | null>;
}

interface NDKSigner {
    /**
     * Synchronously get the public key of the signer.
     * @throws {Error} "Not ready" when the signer is not ready to provide a pubkey synchronously (e.g., NIP-07 or NIP-46 signers)
     * @returns The public key in hex format
     */
    get pubkey(): string;
    /**
     * Blocks until the signer is ready and returns the associated NDKUser.
     * @returns A promise that resolves to the NDKUser instance.
     */
    blockUntilReady(): Promise<NDKUser>;
    /**
     * Getter for the user property.
     * @returns A promise that resolves to the NDKUser instance.
     */
    user(): Promise<NDKUser>;
    get userSync(): NDKUser;
    /**
     * Signs the given Nostr event.
     * @param event - The Nostr event to be signed.
     * @returns A promise that resolves to the signature of the signed event.
     */
    sign(event: NostrEvent): Promise<string>;
    /**
     * Getter for the preferred relays.
     * @returns A promise containing a simple map of preferred relays and their read/write policies.
     */
    relays?(ndk?: NDK): Promise<NDKRelay[]>;
    /**
     * Determine the types of encryption (by nip) that this signer can perform.
     * Implementing classes SHOULD return a value even for legacy (only nip04) third party signers.
     * @nip Optionally returns an array with single supported nip or empty, to check for truthy or falsy.
     * @return A promised list of any (or none) of these strings  ['nip04', 'nip44']
     */
    encryptionEnabled?(scheme?: NDKEncryptionScheme): Promise<NDKEncryptionScheme[]>;
    /**
     * Encrypts the given Nostr event for the given recipient.
     * Implementing classes SHOULD equate legacy (only nip04) to nip == `nip04` || undefined
     * @param recipient - The recipient (pubkey or conversationKey) of the encrypted value.
     * @param value - The value to be encrypted.
     * @param nip - which NIP is being implemented ('nip04', 'nip44')
     */
    encrypt(recipient: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
    /**
     * Decrypts the given value.
     * Implementing classes SHOULD equate legacy (only nip04) to nip == `nip04` || undefined
     * @param sender - The sender (pubkey or conversationKey) of the encrypted value
     * @param value - The value to be decrypted
     * @param scheme - which NIP is being implemented ('nip04', 'nip44', 'nip49')
     */
    decrypt(sender: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
    /**
     * Serializes the signer's essential data into a storable format.
     * @returns A JSON string containing the type and payload.
     */
    toPayload(): string;
}

type NDKPoolStats = {
    total: number;
    connected: number;
    disconnected: number;
    connecting: number;
};
/**
 * Handles connections to all relays. A single pool should be used per NDK instance.
 *
 * @emit connecting - Emitted when a relay in the pool is connecting.
 * @emit connect - Emitted when all relays in the pool are connected, or when the specified timeout has elapsed, and some relays are connected.
 * @emit notice - Emitted when a relay in the pool sends a notice.
 * @emit flapping - Emitted when a relay in the pool is flapping.
 * @emit relay:connect - Emitted when a relay in the pool connects.
 * @emit relay:ready - Emitted when a relay in the pool is ready to serve requests.
 * @emit relay:disconnect - Emitted when a relay in the pool disconnects.
 */
declare class NDKPool extends EventEmitter<{
    notice: (relay: NDKRelay, notice: string) => void;
    flapping: (relay: NDKRelay) => void;
    connect: () => void;
    "relay:connecting": (relay: NDKRelay) => void;
    /**
     * Emitted when a relay in the pool connects.
     * @param relay - The relay that connected.
     */
    "relay:connect": (relay: NDKRelay) => void;
    "relay:ready": (relay: NDKRelay) => void;
    "relay:disconnect": (relay: NDKRelay) => void;
    "relay:auth": (relay: NDKRelay, challenge: string) => void;
    "relay:authed": (relay: NDKRelay) => void;
}> {
    private _relays;
    private status;
    autoConnectRelays: Set<string>;
    private debug;
    private temporaryRelayTimers;
    private flappingRelays;
    private backoffTimes;
    private ndk;
    private disconnectionTimes;
    private systemEventDetector?;
    /**
     * @param relayUrls - The URLs of the relays to connect to.
     * @param ndk - The NDK instance.
     * @param opts - Options for the pool.
     */
    constructor(relayUrls: WebSocket["url"][], ndk: NDK, { debug, name, }?: {
        debug?: debug$1.Debugger;
        name?: string;
    });
    get relays(): Map<string, NDKRelay>;
    set relayUrls(urls: WebSocket["url"][]);
    private _name;
    get name(): string;
    set name(name: string);
    /**
     * Adds a relay to the pool, and sets a timer to remove it if it is not used within the specified time.
     * @param relay - The relay to add to the pool.
     * @param removeIfUnusedAfter - The time in milliseconds to wait before removing the relay from the pool after it is no longer used.
     */
    useTemporaryRelay(relay: NDKRelay, removeIfUnusedAfter?: number, filters?: NDKFilter[] | string): void;
    /**
     * Adds a relay to the pool.
     *
     * @param relay - The relay to add to the pool.
     * @param connect - Whether or not to connect to the relay.
     */
    addRelay(relay: NDKRelay, connect?: boolean): void;
    /**
     * Removes a relay from the pool.
     * @param relayUrl - The URL of the relay to remove.
     * @returns {boolean} True if the relay was removed, false if it was not found.
     */
    removeRelay(relayUrl: string): boolean;
    /**
     * Checks whether a relay is already connected in the pool.
     */
    isRelayConnected(url: WebSocket["url"]): boolean;
    /**
     * Fetches a relay from the pool, or creates a new one if it does not exist.
     *
     * New relays will be attempted to be connected.
     */
    getRelay(url: WebSocket["url"], connect?: boolean, temporary?: boolean, filters?: NDKFilter[]): NDKRelay;
    private handleRelayConnect;
    private handleRelayReady;
    /**
     * Attempts to establish a connection to each relay in the pool.
     *
     * @async
     * @param {number} [timeoutMs] - Optional timeout in milliseconds for each connection attempt.
     * @returns {Promise<void>} A promise that resolves when all connection attempts have completed.
     * @throws {Error} If any of the connection attempts result in an error or timeout.
     */
    connect(timeoutMs?: number): Promise<void>;
    private checkOnFlappingRelays;
    /**
     * Records when a relay disconnects to detect system-wide events
     */
    private recordDisconnection;
    /**
     * Checks if multiple relays disconnected simultaneously, indicating a system event
     */
    private checkForSystemWideDisconnection;
    /**
     * Handles system-wide reconnection (e.g., after sleep/wake or network change)
     */
    private handleSystemWideReconnection;
    private handleFlapping;
    size(): number;
    /**
     * Returns the status of each relay in the pool.
     * @returns {NDKPoolStats} An object containing the number of relays in each status.
     */
    stats(): NDKPoolStats;
    connectedRelays(): NDKRelay[];
    permanentAndConnectedRelays(): NDKRelay[];
    /**
     * Get a list of all relay urls in the pool.
     */
    urls(): string[];
}

/**
 * NDKAuthPolicies are functions that are called when a relay requests authentication
 * so that you can define a behavior for your application.
 *
 * @param relay The relay that requested authentication.
 * @param challenge The challenge that the relay sent.
 */
type NDKAuthPolicy = (relay: NDKRelay, challenge: string) => Promise<boolean | undefined | NDKEvent>;

type NDKFilterFingerprint = string;

type NDKSubscriptionId = string;
/**
 * This class monitors active subscriptions.
 */
declare class NDKSubscriptionManager {
    subscriptions: Map<NDKSubscriptionId, NDKSubscription>;
    seenEvents: LRUCache<string, NDKRelay[]>;
    constructor();
    add(sub: NDKSubscription): void;
    seenEvent(eventId: NDKEventId, relay: NDKRelay): void;
    /**
     * Whenever an event comes in, this function is called.
     * This function matches the received event against all the
     * known (i.e. active) NDKSubscriptions, and if it matches,
     * it sends the event to the subscription.
     *
     * This is the single place in the codebase that matches
     * incoming events with parties interested in the event.
     *
     * This is also what allows for reactivity in NDK apps, such that
     * whenever an active subscription receives an event that some
     * other active subscription would want to receive, both receive it.
     *
     * TODO This also allows for subscriptions that overlap in meaning
     * to be collapsed into one.
     *
     * I.e. if a subscription with filter: kinds: [1], authors: [alice]
     * is created and EOSEs, and then a subsequent subscription with
     * kinds: [1], authors: [alice] is created, once the second subscription
     * EOSEs we can safely close it, increment its refCount and close it,
     * and when the first subscription receives a new event from Alice this
     * code will make the second subscription receive the event even though
     * it has no active subscription on a relay.
     * @param event Raw event received from a relay
     * @param relay Relay that sent the event
     * @param optimisticPublish Whether the event is coming from an optimistic publish
     */
    dispatchEvent(event: NostrEvent, relay?: NDKRelay, optimisticPublish?: boolean): void;
}

type Item = {
    subscription: NDKSubscription;
    filters: NDKFilter[];
};
declare enum NDKRelaySubscriptionStatus {
    INITIAL = 0,
    /**
     * The subscription is pending execution.
     */
    PENDING = 1,
    /**
     * The subscription is waiting for the relay to be ready.
     */
    WAITING = 2,
    /**
     * The subscription is currently running.
     */
    RUNNING = 3,
    CLOSED = 4
}
/**
 * Groups together a number of NDKSubscriptions (as created by the user),
 * filters (as computed internally), executed, or to be executed, within
 * a single specific relay.
 */
declare class NDKRelaySubscription {
    fingerprint: NDKFilterFingerprint;
    items: Map<NDKSubscriptionInternalId, Item>;
    topSubManager: NDKSubscriptionManager;
    debug: debug.Debugger;
    /**
     * Tracks the status of this REQ.
     */
    status: NDKRelaySubscriptionStatus;
    onClose?: (sub: NDKRelaySubscription) => void;
    private relay;
    /**
     * Whether this subscription has reached EOSE.
     */
    private eosed;
    /**
     * Timeout at which this subscription will
     * start executing.
     */
    private executionTimer?;
    /**
     * Track the time at which this subscription will fire.
     */
    private fireTime?;
    /**
     * The delay type that the current fireTime was calculated with.
     */
    private delayType?;
    /**
     * The filters that have been executed.
     */
    executeFilters?: NDKFilter[];
    readonly id: string;
    /**
     *
     * @param fingerprint The fingerprint of this subscription.
     */
    constructor(relay: NDKRelay, fingerprint: NDKFilterFingerprint | null, topSubManager: NDKSubscriptionManager);
    private _subId?;
    get subId(): string;
    private subIdParts;
    private addSubIdPart;
    addItem(subscription: NDKSubscription, filters: NDKFilter[]): void;
    /**
     * A subscription has been closed, remove it from the list of items.
     * @param subscription
     */
    removeItem(subscription: NDKSubscription): void;
    private close;
    cleanup(): void;
    private evaluateExecutionPlan;
    private schedule;
    private executeOnRelayReady;
    private finalizeSubId;
    private reExecuteAfterAuth;
    private execute;
    onstart(): void;
    onevent(event: NostrEvent): void;
    oneose(subId: string): void;
    onclose(_reason?: string): void;
    onclosed(reason?: string): void;
    /**
     * Grabs the filters from all the subscriptions
     * and merges them into a single filter.
     */
    private compileFilters;
}

declare class NDKRelayConnectivity {
    private ndkRelay;
    private ws?;
    private _status;
    private timeoutMs?;
    private connectedAt?;
    private _connectionStats;
    private debug;
    netDebug?: NDKNetDebug;
    private connectTimeout;
    private reconnectTimeout;
    private ndk?;
    openSubs: Map<string, NDKRelaySubscription>;
    private openCountRequests;
    private openEventPublishes;
    private pendingAuthPublishes;
    private serial;
    baseEoseTimeout: number;
    private keepalive?;
    private wsStateMonitor?;
    private sleepDetector?;
    private lastSleepCheck;
    private lastMessageSent;
    private wasIdle;
    constructor(ndkRelay: NDKRelay, ndk?: NDK);
    /**
     * Sets up keepalive, WebSocket state monitoring, and sleep detection
     */
    private setupMonitoring;
    /**
     * Handles detection of a stale connection by cleaning up and triggering reconnection.
     */
    private handleStaleConnection;
    /**
     * Handles possible system wake event
     */
    private handlePossibleWake;
    /**
     * Resets the reconnection state for system-wide events
     * Used by NDKPool when detecting system sleep/wake
     */
    resetReconnectionState(): void;
    /**
     * Connects to the NDK relay and handles the connection lifecycle.
     *
     * This method attempts to establish a WebSocket connection to the NDK relay specified in the `ndkRelay` object.
     * If the connection is successful, it updates the connection statistics, sets the connection status to `CONNECTED`,
     * and emits `connect` and `ready` events on the `ndkRelay` object.
     *
     * If the connection attempt fails, it handles the error by either initiating a reconnection attempt or emitting a
     * `delayed-connect` event on the `ndkRelay` object, depending on the `reconnect` parameter.
     *
     * @param timeoutMs - The timeout in milliseconds for the connection attempt. If not provided, the default timeout from the `ndkRelay` object is used.
     * @param reconnect - Indicates whether a reconnection should be attempted if the connection fails. Defaults to `true`.
     * @returns A Promise that resolves when the connection is established, or rejects if the connection fails.
     */
    connect(timeoutMs?: number, reconnect?: boolean): Promise<void>;
    /**
     * Disconnects the WebSocket connection to the NDK relay.
     * This method sets the connection status to `NDKRelayStatus.DISCONNECTING`,
     * attempts to close the WebSocket connection, and sets the status to
     * `NDKRelayStatus.DISCONNECTED` if the disconnect operation fails.
     */
    disconnect(): void;
    /**
     * Handles the error that occurred when attempting to connect to the NDK relay.
     * If `reconnect` is `true`, this method will initiate a reconnection attempt.
     * Otherwise, it will emit a `delayed-connect` event on the `ndkRelay` object,
     * indicating that a reconnection should be attempted after a delay.
     *
     * @param reconnect - Indicates whether a reconnection should be attempted.
     */
    onConnectionError(reconnect: boolean): void;
    /**
     * Handles the connection event when the WebSocket connection is established.
     * This method is called when the WebSocket connection is successfully opened.
     * It clears any existing connection and reconnection timeouts, updates the connection statistics,
     * sets the connection status to `CONNECTED`, and emits `connect` and `ready` events on the `ndkRelay` object.
     */
    private onConnect;
    /**
     * Handles the disconnection event when the WebSocket connection is closed.
     * This method is called when the WebSocket connection is successfully closed.
     * It updates the connection statistics, sets the connection status to `DISCONNECTED`,
     * initiates a reconnection attempt if we didn't disconnect ourselves,
     * and emits a `disconnect` event on the `ndkRelay` object.
     */
    private onDisconnect;
    /**
     * Handles incoming messages from the NDK relay WebSocket connection.
     * This method is called whenever a message is received from the relay.
     * It parses the message data and dispatches the appropriate handling logic based on the message type.
     *
     * @param event - The MessageEvent containing the received message data.
     */
    private onMessage;
    /**
     * Handles an authentication request from the NDK relay.
     *
     * If an authentication policy is configured, it will be used to authenticate the connection.
     * Otherwise, the `auth` event will be emitted to allow the application to handle the authentication.
     *
     * @param challenge - The authentication challenge provided by the NDK relay.
     */
    private onAuthRequested;
    /**
     * Handles errors that occur on the WebSocket connection to the relay.
     * @param error - The error or event that occurred.
     */
    private onError;
    /**
     * Gets the current status of the NDK relay connection.
     * @returns {NDKRelayStatus} The current status of the NDK relay connection.
     */
    get status(): NDKRelayStatus;
    /**
     * Checks if the NDK relay connection is currently available.
     * @returns {boolean} `true` if the relay connection is in the `CONNECTED` status, `false` otherwise.
     */
    isAvailable(): boolean;
    /**
     * Checks if the NDK relay connection is flapping, which means the connection is rapidly
     * disconnecting and reconnecting. This is determined by analyzing the durations of the
     * last three connection attempts. If the standard deviation of the durations is less
     * than 1000 milliseconds, the connection is considered to be flapping.
     *
     * @returns {boolean} `true` if the connection is flapping, `false` otherwise.
     */
    private isFlapping;
    /**
     * Handles a notice received from the NDK relay.
     * If the notice indicates the relay is complaining (e.g. "too many" or "maximum"),
     * the method disconnects from the relay and attempts to reconnect after a 2-second delay.
     * A debug message is logged with the relay URL and the notice text.
     * The "notice" event is emitted on the ndkRelay instance with the notice text.
     *
     * @param notice - The notice text received from the NDK relay.
     */
    private onNotice;
    /**
     * Attempts to reconnect to the NDK relay after a connection is lost.
     * This function is called recursively to handle multiple reconnection attempts.
     * It checks if the relay is flapping and emits a "flapping" event if so.
     * It then calculates a delay before the next reconnection attempt based on the number of previous attempts.
     * The function sets a timeout to execute the next reconnection attempt after the calculated delay.
     * If the maximum number of reconnection attempts is reached, a debug message is logged.
     *
     * @param attempt - The current attempt number (default is 0).
     */
    private handleReconnection;
    /**
     * Sends a message to the NDK relay if the connection is in the CONNECTED state and the WebSocket is open.
     * If the connection is not in the CONNECTED state or the WebSocket is not open, logs a debug message and throws an error.
     *
     * @param message - The message to send to the NDK relay.
     * @throws {Error} If attempting to send on a closed relay connection.
     */
    send(message: string): Promise<void>;
    /**
     * Authenticates the NDK event by sending it to the NDK relay and returning a promise that resolves with the result.
     *
     * @param event - The NDK event to authenticate.
     * @returns A promise that resolves with the authentication result.
     */
    private auth;
    /**
     * Clears all pending publish promises by rejecting them with the provided error.
     * This is called on disconnection to prevent memory leaks and ensure promises
     * don't hang indefinitely.
     * @param error The error to reject the promises with
     */
    private clearPendingPublishes;
    /**
     * Retries all pending publishes that failed due to auth-required.
     * Called after successful authentication.
     */
    private retryPendingAuthPublishes;
    /**
     * Rejects all pending publishes that failed due to auth-required.
     * Called when authentication fails.
     */
    private rejectPendingAuthPublishes;
    /**
     * Publishes an NDK event to the relay and returns a promise that resolves with the result.
     *
     * @param event - The NDK event to publish.
     * @returns A promise that resolves with the result of the event publication.
     * @throws {Error} If attempting to publish on a closed relay connection.
     */
    publish(event: NostrEvent): Promise<string>;
    /**
     * Counts the number of events that match the provided filters.
     *
     * @param filters - The filters to apply to the count request.
     * @param params - An optional object containing a custom id for the count request.
     * @returns A promise that resolves with the count result including optional HLL data.
     * @throws {Error} If attempting to send the count request on a closed relay connection.
     */
    count(filters: NDKFilter[], params: {
        id?: string | null;
    }): Promise<NDKCountResult>;
    close(subId: string, reason?: string): void;
    /**
     * Subscribes to the NDK relay with the provided filters and parameters.
     *
     * @param filters - The filters to apply to the subscription.
     * @param params - The subscription parameters, including an optional custom id.
     * @returns A new NDKRelaySubscription instance.
     */
    req(relaySub: NDKRelaySubscription): void;
    /**
     * Utility functions to update the connection stats.
     */
    private updateConnectionStats;
    /** Returns the connection stats. */
    get connectionStats(): NDKRelayConnectionStats;
    /** Returns the relay URL */
    get url(): WebSocket["url"];
    get connected(): boolean;
}

/**
 * NIP-11: Relay Information Document
 * https://github.com/nostr-protocol/nips/blob/master/11.md
 */
interface NDKRelayInformation {
    name?: string;
    description?: string;
    banner?: string;
    icon?: string;
    pubkey?: string;
    contact?: string;
    supported_nips?: number[];
    software?: string;
    version?: string;
    privacy_policy?: string;
    terms_of_service?: string;
    limitation?: {
        max_message_length?: number;
        max_subscriptions?: number;
        max_subid_length?: number;
        max_limit?: number;
        max_event_tags?: number;
        max_content_length?: number;
        min_pow_difficulty?: number;
        auth_required?: boolean;
        payment_required?: boolean;
        restricted_writes?: boolean;
        created_at_lower_limit?: number;
        created_at_upper_limit?: number;
        default_limit?: number;
    };
    retention?: Array<{
        kinds?: Array<number | [number, number]>;
        time?: number | null;
        count?: number;
    }>;
    relay_countries?: string[];
    language_tags?: string[];
    tags?: string[];
    posting_policy?: string;
    payments_url?: string;
    fees?: {
        admission?: Array<{
            amount: number;
            unit: string;
        }>;
        subscription?: Array<{
            amount: number;
            unit: string;
            period: number;
        }>;
        publication?: Array<{
            kinds?: number[];
            amount: number;
            unit: string;
        }>;
    };
    [key: string]: unknown;
}

type NDKRelayScore = number;

/**
 * The subscription manager of an NDKRelay is in charge of orchestrating the subscriptions
 * that are created and closed in a given relay.
 *
 * The manager is responsible for:
 * * restarting subscriptions when they are unexpectedly closed
 * * scheduling subscriptions that are received before the relay is connected
 * * grouping similar subscriptions to be compiled into individual REQs
 */
declare class NDKRelaySubscriptionManager {
    private relay;
    subscriptions: Map<NDKFilterFingerprint, NDKRelaySubscription[]>;
    private generalSubManager;
    /**
     * @param relay - The relay instance.
     * @param generalSubManager - The subscription manager instance.
     */
    constructor(relay: NDKRelay, generalSubManager: NDKSubscriptionManager);
    /**
     * Adds a subscription to the manager.
     */
    addSubscription(sub: NDKSubscription, filters: NDKFilter[]): void;
    createSubscription(_sub: NDKSubscription, _filters: NDKFilter[], fingerprint?: NDKFilterFingerprint): NDKRelaySubscription;
    private onRelaySubscriptionClose;
}

/**
 * Protocol handler function type for handling custom relay messages.
 * @param relay The relay that received the message
 * @param message The parsed message array from the relay
 */
type NDKProtocolHandler = (relay: NDKRelay, message: unknown[]) => void;
declare enum NDKRelayStatus {
    DISCONNECTING = 0,// 0
    DISCONNECTED = 1,// 1
    RECONNECTING = 2,// 2
    FLAPPING = 3,// 3
    CONNECTING = 4,// 4
    CONNECTED = 5,// 5
    AUTH_REQUESTED = 6,// 6
    AUTHENTICATING = 7,// 7
    AUTHENTICATED = 8
}
interface NDKRelayConnectionStats {
    /**
     * The number of times a connection has been attempted.
     */
    attempts: number;
    /**
     * The number of times a connection has been successfully established.
     */
    success: number;
    /**
     * The durations of the last 100 connections in milliseconds.
     */
    durations: number[];
    /**
     * The time the current connection was established in milliseconds.
     */
    connectedAt?: number;
    /**
     * Timestamp of the next reconnection attempt.
     */
    nextReconnectAt?: number;
    /**
     * Signature validation ratio for this relay.
     * @see NDKRelayOptions.validationRatio
     */
    validationRatio?: number;
}
/**
 * The NDKRelay class represents a connection to a relay.
 *
 * @emits NDKRelay#connect
 * @emits NDKRelay#ready
 * @emits NDKRelay#disconnect
 * @emits NDKRelay#notice
 * @emits NDKRelay#event
 * @emits NDKRelay#published when an event is published to the relay
 * @emits NDKRelay#publish:failed when an event fails to publish to the relay
 * @emits NDKRelay#eose when the relay has reached the end of stored events
 * @emits NDKRelay#auth when the relay requires authentication
 * @emits NDKRelay#authed when the relay has authenticated
 * @emits NDKRelay#delayed-connect when the relay will wait before reconnecting
 */
declare class NDKRelay extends EventEmitter<{
    connect: () => void;
    ready: () => void;
    /**
     * Emitted when the relay has reached the end of stored events.
     */
    disconnect: () => void;
    flapping: (stats: NDKRelayConnectionStats) => void;
    notice: (notice: string) => void;
    auth: (challenge: string) => void;
    authed: () => void;
    "auth:failed": (error: Error) => void;
    published: (event: NDKEvent) => void;
    "publish:failed": (event: NDKEvent, error: Error) => void;
    "delayed-connect": (delayInMs: number) => void;
}> {
    readonly url: WebSocket["url"];
    readonly scores: Map<NDKUser, NDKRelayScore>;
    connectivity: NDKRelayConnectivity;
    subs: NDKRelaySubscriptionManager;
    private publisher;
    authPolicy?: NDKAuthPolicy;
    /**
     * Protocol handlers for custom relay message types (e.g., NEG-OPEN, NEG-MSG).
     * Allows external packages to handle non-standard relay messages.
     */
    private protocolHandlers;
    /**
     * Cached relay information from NIP-11.
     */
    private _relayInfo?;
    /**
     * The lowest validation ratio this relay can reach.
     */
    lowestValidationRatio?: number;
    /**
     * Current validation ratio this relay is targeting.
     */
    targetValidationRatio?: number;
    validationRatioFn?: (relay: NDKRelay, validatedCount: number, nonValidatedCount: number) => number;
    /**
     * This tracks events that have been seen by this relay
     * with a valid signature.
     */
    validatedEventCount: number;
    /**
     * This tracks events that have been seen by this relay
     * but have not been validated.
     */
    nonValidatedEventCount: number;
    /**
     * Whether this relay is trusted.
     *
     * Trusted relay's events do not get their signature verified.
     */
    trusted: boolean;
    complaining: boolean;
    readonly debug: debug$1.Debugger;
    static defaultValidationRatioUpdateFn: (relay: NDKRelay, validatedCount: number, _nonValidatedCount: number) => number;
    constructor(url: WebSocket["url"], authPolicy: NDKAuthPolicy | undefined, ndk: NDK);
    private updateValidationRatio;
    get status(): NDKRelayStatus;
    get connectionStats(): NDKRelayConnectionStats;
    /**
     * Connects to the relay.
     */
    connect(timeoutMs?: number, reconnect?: boolean): Promise<void>;
    /**
     * Disconnects from the relay.
     */
    disconnect(): void;
    /**
     * Queues or executes the subscription of a specific set of filters
     * within this relay.
     *
     * @param subscription NDKSubscription this filters belong to.
     * @param filters Filters to execute
     */
    subscribe(subscription: NDKSubscription, filters: NDKFilter[]): void;
    /**
     * Publishes an event to the relay with an optional timeout.
     *
     * If the relay is not connected, the event will be published when the relay connects,
     * unless the timeout is reached before the relay connects.
     *
     * @param event The event to publish
     * @param timeoutMs The timeout for the publish operation in milliseconds
     * @returns A promise that resolves when the event has been published or rejects if the operation times out
     */
    publish(event: NDKEvent, timeoutMs?: number): Promise<boolean>;
    referenceTags(): NDKTag[];
    addValidatedEvent(): void;
    addNonValidatedEvent(): void;
    /**
     * The current validation ratio this relay has achieved.
     */
    get validationRatio(): number;
    shouldValidateEvent(): boolean;
    get connected(): boolean;
    req: (relaySub: NDKRelaySubscription) => void;
    close: (subId: string) => void;
    /**
     * Registers a protocol handler for a specific message type.
     * This allows external packages to handle custom relay messages (e.g., NIP-77 NEG-* messages).
     *
     * @param messageType The message type to handle (e.g., "NEG-OPEN", "NEG-MSG")
     * @param handler The function to call when a message of this type is received
     *
     * @example
     * ```typescript
     * relay.registerProtocolHandler('NEG-MSG', (relay, message) => {
     *   console.log('Received NEG-MSG:', message);
     * });
     * ```
     */
    registerProtocolHandler(messageType: string, handler: NDKProtocolHandler): void;
    /**
     * Unregisters a protocol handler for a specific message type.
     *
     * @param messageType The message type to stop handling
     */
    unregisterProtocolHandler(messageType: string): void;
    /**
     * Checks if a protocol handler is registered for a message type.
     * This is used internally by the connectivity layer to route messages.
     *
     * @internal
     * @param messageType The message type to check
     * @returns The handler function if registered, undefined otherwise
     */
    getProtocolHandler(messageType: string): NDKProtocolHandler | undefined;
    /**
     * Fetches relay information (NIP-11) from the relay.
     * Results are cached in persistent storage when cache adapter is available (24-hour TTL).
     * Falls back to in-memory cache. Pass force=true to bypass all caches.
     *
     * @param force Force a fresh fetch, bypassing all caches
     * @returns The relay information document
     * @throws Error if the fetch fails
     *
     * @example
     * ```typescript
     * const info = await relay.fetchInfo();
     * console.log(`Relay: ${info.name}`);
     * console.log(`Supported NIPs: ${info.supported_nips?.join(', ')}`);
     * ```
     */
    fetchInfo(force?: boolean): Promise<NDKRelayInformation>;
    /**
     * Returns cached relay information if available, undefined otherwise.
     * Use fetchInfo() to retrieve fresh information.
     */
    get info(): NDKRelayInformation | undefined;
}

type NDKSubscriptionInternalId = string;

type NDKSubscriptionDelayedType = "at-least" | "at-most";
type NDKFilter<K extends number = NDKKind> = {
    ids?: string[];
    kinds?: K[];
    authors?: string[];
    since?: number;
    until?: number;
    limit?: number;
    search?: string;
    [key: `#${string}`]: string[] | undefined;
};
declare enum NDKSubscriptionCacheUsage {
    ONLY_CACHE = "ONLY_CACHE",
    CACHE_FIRST = "CACHE_FIRST",
    PARALLEL = "PARALLEL",
    ONLY_RELAY = "ONLY_RELAY"
}
interface NDKSubscriptionOptions {
    /**
     * Whether to close the subscription when all relays have reached the end of the event stream.
     * @default false
     */
    closeOnEose?: boolean;
    cacheUsage?: NDKSubscriptionCacheUsage;
    /**
     * Whether to skip caching events coming from this subscription
     **/
    dontSaveToCache?: boolean;
    /**
     * Groupable subscriptions are created with a slight time
     * delayed to allow similar filters to be grouped together.
     */
    groupable?: boolean;
    /**
     * The delay to use when grouping subscriptions, specified in milliseconds.
     * @default 100
     * @example
     * const sub1 = ndk.subscribe({ kinds: [1], authors: ["alice"] }, { groupableDelay: 100 });
     * const sub2 = ndk.subscribe({ kinds: [0], authors: ["alice"] }, { groupableDelay: 1000 });
     * // sub1 and sub2 will be grouped together and executed 100ms after sub1 was created
     */
    groupableDelay?: number;
    /**
     * Specifies how this delay should be interpreted.
     * "at-least" means "wait at least this long before sending the subscription"
     * "at-most" means "wait at most this long before sending the subscription"
     * @default "at-most"
     * @example
     * const sub1 = ndk.subscribe({ kinds: [1], authors: ["alice"] }, { groupableDelay: 100, groupableDelayType: "at-least" }); // 3 args
     * const sub2 = ndk.subscribe({ kinds: [0], authors: ["alice"] }, { groupableDelay: 1000, groupableDelayType: "at-most" }); // 3 args
     * // sub1 and sub2 will be grouped together and executed 1000ms after sub1 was created
     */
    groupableDelayType?: NDKSubscriptionDelayedType;
    /**
     * The subscription ID to use for the subscription.
     */
    subId?: string;
    /**
     * Pool to use
     */
    pool?: NDKPool;
    /**
     * Skip signature verification
     * @default false
     */
    skipVerification?: boolean;
    /**
     * Skip event validation. Event validation, checks whether received
     * kinds conform to what the expected schema of that kind should look like.rtwle
     * @default false
     */
    skipValidation?: boolean;
    /**
     * Skip emitting on events before they are received from a relay. (skip optimistic publish)
     * @default false
     */
    skipOptimisticPublishEvent?: boolean;
    /**
     * Remove filter constraints when querying the cache.
     *
     * This allows setting more aggressive filters that will be removed when hitting the cache.
     *
     * Useful uses of this include removing `since` or `until` constraints or `limit` filters.
     *
     * @example
     * ndk.subscribe({ kinds: [1], since: 1710000000, limit: 10 }, { cacheUnconstrainFilter: ['since', 'limit'] }); // 3 args
     *
     * This will hit relays with the since and limit constraints, while loading from the cache without them.
     */
    cacheUnconstrainFilter?: (keyof NDKFilter)[];
    /**
     * Whether to wrap events in kind-specific classes when possible.
     * @default false
     */
    wrap?: boolean;
    /**
     * Explicit relay set to use for this subscription instead of calculating it.
     * If `relayUrls` is also provided in the options, this `relaySet` takes precedence.
     * @since 2.13.0 Moved from `ndk.subscribe` parameter to options.
     */
    relaySet?: NDKRelaySet;
    /**
     * Explicit relay URLs to use for this subscription instead of calculating the relay set.
     * An `NDKRelaySet` will be created internally from these URLs.
     * If `relaySet` is also provided in the options, the explicit `relaySet` takes precedence over these URLs.
     * @since 2.13.0
     */
    relayUrls?: string[];
    /**
     * When set, the cache will be queried first, and, when hitting relays,
     * a `since` filter will be added to the subscription that is one second
     * after the last event received from the cache.
     *
     * This option implies cacheUsage: CACHE_FIRST.
     */
    addSinceFromCache?: boolean;
    /**
     * Include muted events in subscription results.
     * When false (default), events that match ndk.muteFilter are filtered out.
     * When true, muted events are included.
     * @default false
     */
    includeMuted?: boolean;
    /**
     * Number of relays to query for each author in the subscription.
     * This controls the outbox model relay selection when the filter has authors.
     * Higher values improve redundancy but increase bandwidth usage.
     * @default 2
     * @example
     * // Query 3 relays for each author
     * ndk.subscribe(
     *   { kinds: [1], authors: ["alice", "bob"] },
     *   { relayGoalPerAuthor: 3 }
     * );
     * @example
     * // Use all available relays for each author
     * ndk.subscribe(
     *   { kinds: [1], authors: ["alice", "bob"] },
     *   { relayGoalPerAuthor: Infinity }
     * );
     */
    relayGoalPerAuthor?: number;
    /**
     * Called for each event received by the subscription.
     * This eliminates the race condition of subscribing and then attaching event handlers.
     * @param event The received NDKEvent.
     * @param relay The relay the event was received from (undefined if from cache).
     * @param subscription The subscription that received the event.
     * @param fromCache Whether the event came from cache.
     * @param optimisticPublish Whether this is an optimistic publish event.
     */
    onEvent?: (event: NDKEvent, relay?: NDKRelay, subscription?: NDKSubscription, fromCache?: boolean, optimisticPublish?: boolean) => void;
    /**
     * Called with a batch of events from cache.
     * When this is provided, cached events are processed in batch instead of individually.
     * @param events Array of cached events to process in batch.
     */
    onEvents?: (events: NDKEvent[]) => void;
    /**
     * Called when the subscription receives an EOSE (End of Stored Events) marker
     * from all connected relays.
     * @param subscription The subscription that reached EOSE.
     */
    onEose?: (subscription: NDKSubscription) => void;
    /**
     * Called when a duplicate event is received by the subscription.
     * @param event The duplicate event received by the subscription.
     * @param relay The relay that received the event (undefined if from cache).
     * @param timeSinceFirstSeen The time elapsed since the first time the event was seen.
     * @param subscription The subscription that received the event.
     * @param fromCache Whether the event came from cache.
     * @param optimisticPublish Whether this is an optimistic publish event.
     */
    onEventDup?: (event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, timeSinceFirstSeen: number, subscription: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
    /**
     * Called when the subscription is closed.
     * @param subscription The subscription that was closed.
     */
    onClose?: (subscription: NDKSubscription) => void;
    /**
     * When true, only accept events from the relays specified in relaySet/relayUrls.
     * When false (default), events matching the filter from any relay will be delivered
     * to this subscription (cross-subscription matching behavior).
     *
     * This is useful when you need strict relay provenance, such as:
     * - Fetching events exclusively from a specific relay
     * - Implementing relay-based isolation or routing
     * - Testing relay-specific behavior
     *
     * @default false
     * @example
     * // Only receive events from relay-a.com, ignore matches from other relays
     * ndk.subscribe(
     *   { kinds: [1] },
     *   { relayUrls: ["wss://relay-a.com"], exclusiveRelay: true }
     * );
     */
    exclusiveRelay?: boolean;
}
/**
 * Represents a subscription to an NDK event stream.
 *
 * @emits event
 * Emitted when an event is received by the subscription.
 * * ({NDKEvent} event - The event received by the subscription,
 * * {NDKRelay} relay - The relay that received the event,
 * * {NDKSubscription} subscription - The subscription that received the event.)
 *
 * @emits event:dup
 * Emitted when a duplicate event is received by the subscription.
 * * {NDKEvent} event - The duplicate event received by the subscription.
 * * {NDKRelay} relay - The relay that received the event.
 * * {number} timeSinceFirstSeen - The time elapsed since the first time the event was seen.
 * * {NDKSubscription} subscription - The subscription that received the event.
 *
 * @emits cacheEose - Emitted when the cache adapter has reached the end of the events it had.
 *
 * @emits eose - Emitted when all relays have reached the end of the event stream.
 * * {NDKSubscription} subscription - The subscription that received EOSE.
 *
 * @emits close - Emitted when the subscription is closed.
 * * {NDKSubscription} subscription - The subscription that was closed.
 *
 * @example
 * const sub = ndk.subscribe(
 *   { kinds: [1] }, // Get all kind:1s
 *   {
 *     onEvent: (event) => console.log(event.content), // Show the content
 *     onEose: () => console.log("All relays have reached the end of the event stream"),
 *     onClose: () => console.log("Subscription closed")
 *   }
 * );
 * setTimeout(() => sub.stop(), 10000); // Stop the subscription after 10 seconds
 *
 * @description
 * Subscriptions are created using {@link NDK.subscribe}.
 *
 * # Event validation
 * By defaults, subscriptions will validate events to comply with the minimal requirement
 * of each known NIP.
 * This can be disabled by setting the `skipValidation` option to `true`.
 *
 * @example
 * const sub = ndk.subscribe(
 *   { kinds: [1] },
 *   {
 *     skipValidation: false,
 *     onEvent: (event) => console.log(event.content) // Only valid events will be received
 *   }
 * );
 */
declare class NDKSubscription extends EventEmitter<{
    cacheEose: () => void;
    eose: (sub: NDKSubscription) => void;
    close: (sub: NDKSubscription) => void;
    /**
     * Emitted when a duplicate event is received by the subscription.
     * @param event - The duplicate event received by the subscription.
     * @param relay - The relay that received the event.
     * @param timeSinceFirstSeen - The time elapsed since the first time the event was seen.
     * @param sub - The subscription that received the event.
     */
    "event:dup": (event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, timeSinceFirstSeen: number, sub: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
    /**
     * Emitted when an event is received by the subscription.
     * @param event - The event received by the subscription.
     * @param relay - The relay that received the event.
     * @param sub - The subscription that received the event.
     * @param fromCache - Whether the event was received from the cache.
     * @param optimisticPublish - Whether the event was received from an optimistic publish.
     */
    event: (event: NDKSignedEvent, relay: NDKRelay | undefined, sub: NDKSubscription, fromCache: boolean, optimisticPublish: boolean) => void;
    /**
     * Emitted when a relay unilaterally closes the subscription.
     * @param relay
     * @param reason
     * @returns
     */
    closed: (relay: NDKRelay, reason: string) => void;
}> {
    readonly subId?: string;
    readonly filters: NDKFilter[];
    readonly opts: NDKSubscriptionOptions;
    readonly pool: NDKPool;
    readonly skipVerification: boolean;
    readonly skipValidation: boolean;
    readonly exclusiveRelay: boolean;
    /**
     * Tracks the filters as they are executed on each relay
     */
    relayFilters?: Map<WebSocket["url"], NDKFilter[]>;
    relaySet?: NDKRelaySet;
    ndk: NDK;
    debug: debug.Debugger;
    /**
     * Events that have been seen by the subscription, with the time they were first seen.
     */
    eventFirstSeen: Map<string, number>;
    /**
     * Relays that have sent an EOSE.
     */
    eosesSeen: Set<NDKRelay>;
    /**
     * The time the last event was received by the subscription.
     * This is used to calculate when EOSE should be emitted.
     */
    private lastEventReceivedAt;
    /**
     * The most recent event timestamp from cache results.
     * This is used for addSinceFromCache functionality.
     */
    private mostRecentCacheEventTimestamp?;
    internalId: NDKSubscriptionInternalId;
    /**
     * Whether the subscription should close when all relays have reached the end of the event stream.
     */
    closeOnEose: boolean;
    /**
     * Pool monitor callback
     */
    private poolMonitor;
    skipOptimisticPublishEvent: boolean;
    /**
     * Filters to remove when querying the cache.
     */
    cacheUnconstrainFilter?: Array<keyof NDKFilter>;
    constructor(ndk: NDK, filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, subId?: string);
    /**
     * Returns the relays that have not yet sent an EOSE.
     */
    relaysMissingEose(): WebSocket["url"][];
    /**
     * Provides access to the first filter of the subscription for
     * backwards compatibility.
     */
    get filter(): NDKFilter;
    get groupableDelay(): number | undefined;
    get groupableDelayType(): NDKSubscriptionDelayedType;
    isGroupable(): boolean;
    private shouldQueryCache;
    private shouldQueryRelays;
    private shouldWaitForCache;
    /**
     * Start the subscription. This is the main method that should be called
     * after creating a subscription.
     *
     * @param emitCachedEvents - Whether to emit events coming from a synchronous cache
     *
     * When using a synchronous cache, the events will be returned immediately
     * by this function. If you will use those returned events, you should
     * set emitCachedEvents to false to prevent seeing them as duplicate events.
     */
    start(emitCachedEvents?: boolean): NDKEvent[] | null;
    /**
     * We want to monitor for new relays that are coming online, in case
     * they should be part of this subscription.
     */
    private startPoolMonitor;
    onStopped?: () => void;
    stop(): void;
    /**
     * @returns Whether the subscription has an authors filter.
     */
    hasAuthorsFilter(): boolean;
    private startWithCache;
    /**
     * Find available relays that should be part of this subscription and execute in them.
     *
     * Note that this is executed in addition to using the pool monitor, so even if the relay set
     * that is computed (i.e. we don't have any relays available), when relays come online, we will
     * check if we need to execute in them.
     */
    private startWithRelays;
    /**
     * Refresh relay connections when outbox data becomes available.
     * This recalculates which relays should receive this subscription and
     * connects to any newly discovered relays.
     */
    refreshRelayConnections(): void;
    /**
     * Called when an event is received from a relay or the cache
     * @param event
     * @param relay
     * @param fromCache Whether the event was received from the cache
     * @param optimisticPublish Whether this event is coming from an optimistic publish
     */
    eventReceived(event: NDKEvent | NostrEvent, relay: NDKRelay | undefined, fromCache?: boolean, optimisticPublish?: boolean): void;
    /**
     * Optionally wraps, sync or async, and emits the event (if one comes back from the wrapper)
     */
    private emitEvent;
    closedReceived(relay: NDKRelay, reason: string): void;
    private eoseTimeout;
    private eosed;
    eoseReceived(relay: NDKRelay): void;
}

declare class NDKPublishError extends Error {
    errors: Map<NDKRelay, Error>;
    publishedToRelays: Set<NDKRelay>;
    /**
     * Intended relay set where the publishing was intended to happen.
     */
    intendedRelaySet?: NDKRelaySet;
    constructor(message: string, errors: Map<NDKRelay, Error>, publishedToRelays: Set<NDKRelay>, intendedRelaySet?: NDKRelaySet);
    get relayErrors(): string;
}
/**
 * A relay set is a group of relays. This grouping can be short-living, for a single
 * REQ or can be long-lasting, for example for the explicit relay list the user
 * has specified.
 *
 * Requests to relays should be sent through this interface.
 */
declare class NDKRelaySet {
    readonly relays: Set<NDKRelay>;
    private debug;
    private ndk;
    private pool;
    constructor(relays: Set<NDKRelay>, ndk: NDK, pool?: NDKPool);
    /**
     * Adds a relay to this set.
     */
    addRelay(relay: NDKRelay): void;
    get relayUrls(): WebSocket["url"][];
    /**
     * Creates a relay set from a list of relay URLs.
     *
     * If no connection to the relay is found in the pool it will temporarily
     * connect to it.
     *
     * @param relayUrls - list of relay URLs to include in this set
     * @param ndk
     * @param connect - whether to connect to the relay immediately if it was already in the pool but not connected
     * @returns NDKRelaySet
     */
    static fromRelayUrls(relayUrls: readonly string[], ndk: NDK, connect?: boolean, pool?: NDKPool): NDKRelaySet;
    /**
     * Publish an event to all relays in this relay set.
     *
     * This method implements a robust mechanism for publishing events to multiple relays with
     * built-in handling for race conditions, timeouts, and partial failures. The implementation
     * uses a dual-tracking mechanism to ensure accurate reporting of which relays successfully
     * received an event.
     *
     * Key aspects of this implementation:
     *
     * 1. DUAL-TRACKING MECHANISM:
     *    - Promise-based tracking: Records successes/failures from the promises returned by relay.publish()
     *    - Event-based tracking: Listens for 'relay:published' events that indicate successful publishing
     *    This approach ensures we don't miss successful publishes even if there are subsequent errors in
     *    the promise chain.
     *
     * 2. RACE CONDITION HANDLING:
     *    - If a relay emits a success event but later fails in the promise chain, we still count it as a success
     *    - If a relay times out after successfully publishing, we still count it as a success
     *    - All relay operations happen in parallel, with proper tracking regardless of completion order
     *
     * 3. TIMEOUT MANAGEMENT:
     *    - Individual timeouts for each relay operation
     *    - Proper cleanup of timeouts to prevent memory leaks
     *    - Clear timeout error reporting
     *
     * 4. ERROR HANDLING:
     *    - Detailed tracking of specific errors for each failed relay
     *    - Special handling for ephemeral events (which don't expect acknowledgement)
     *    - RequiredRelayCount parameter to control the minimum success threshold
     *
     * @param event Event to publish
     * @param timeoutMs Timeout in milliseconds for each relay publish operation
     * @param requiredRelayCount The minimum number of relays we expect the event to be published to
     * @returns A set of relays the event was published to
     * @throws {NDKPublishError} If the event could not be published to at least `requiredRelayCount` relays
     * @example
     * ```typescript
     * const relaySet = new NDKRelaySet(new Set([relay1, relay2]), ndk);
     * const publishedToRelays = await relaySet.publish(event);
     * // publishedToRelays can contain relay1, relay2, both, or none
     * // depending on which relays the event was successfully published to
     * if (publishedToRelays.size > 0) {
     *   console.log("Event published to at least one relay");
     * }
     * ```
     */
    publish(event: NDKEvent, timeoutMs?: number, requiredRelayCount?: number): Promise<Set<NDKRelay>>;
    get size(): number;
    /**
     * Counts events matching the given filters across all relays in this set.
     *
     * This method implements NIP-45 COUNT with HyperLogLog (HLL) support for
     * accurate cardinality estimation across multiple relays.
     *
     * When relays return HLL data, the counts are merged using the HLL algorithm
     * to avoid double-counting events that appear on multiple relays.
     *
     * @param filters - The filters to count events for
     * @param opts - Optional count options (timeout, custom id)
     * @returns An aggregated count result with the best estimate and per-relay results
     *
     * @example
     * ```typescript
     * const relaySet = new NDKRelaySet(new Set([relay1, relay2]), ndk);
     * const result = await relaySet.count([{ kinds: [1], authors: [pubkey] }]);
     * console.log(`Estimated unique count: ${result.count}`);
     * console.log(`Relay 1 reported: ${result.relayResults.get(relay1.url)?.count}`);
     * ```
     */
    count(filters: NDKFilter | NDKFilter[], opts?: NDKCountOptions): Promise<NDKAggregatedCountResult>;
}

/**
 * Options on how to handle when a relay hint doesn't respond
 * with the requested event.
 *
 * When a tag includes a relay hint, and the relay hint doesn't come back
 * with the event, the fallback options are used to try to fetch the event
 * from somewhere else.
 */
type NDKFetchFallbackOptions = {
    /**
     * Relay set to use as a fallback when the hint relay doesn't respond.
     * If not provided, the normal NDK calculation is used (whether explicit relays or outbox calculation)
     * Default is `undefined`.
     */
    relaySet?: NDKRelaySet;
    /**
     * Type of fallback to use when the hint relay doesn't respond.
     * - "timeout" will wait for a timeout before falling back
     * - "eose" will wait for the EOSE before falling back
     * - "none" will not fall back
     * Default is "timeout".
     */
    type: "timeout" | "eose" | "none";
    /**
     * Timeout in milliseconds for the fallback relay.
     * Default is 1500ms.
     */
    timeout?: number;
};

interface AIGuardrailConfig {
    skip?: Set<string>;
}
type AIGuardrailsMode = boolean | AIGuardrailConfig;

/**
 * AI Guardrails - Runtime validation to catch common mistakes made by LLMs and developers.
 *
 * This module provides a flexible system for warning about or preventing common anti-patterns
 * when using NDK. It's designed to be:
 * - Off by default (zero performance impact in production)
 * - Granularly configurable (can disable specific checks)
 * - Educational (provides actionable error messages)
 *
 * Architecture:
 * - Inline checks for synchronous validation (must block operations)
 * - Hook methods for observational warnings (async, non-blocking)
 * - All guardrail logic organized by domain (ndk, event, relay, etc.)
 * - Core code stays clean - just calls typed hook methods
 *
 * @example Enable all guardrails
 * ```typescript
 * const ndk = new NDK({ aiGuardrails: true });
 * ```
 *
 * @example Enable with exceptions
 * ```typescript
 * const ndk = new NDK({
 *   aiGuardrails: { skip: new Set(['filter-large-limit']) }
 * });
 * ```
 *
 * @example Programmatic control
 * ```typescript
 * ndk.aiGuardrails.skip('filter-large-limit');
 * ndk.aiGuardrails.enable('filter-bech32-in-array');
 * ```
 *
 * @example Temporarily disable for one call
 * ```typescript
 * // Disable all guardrails for one call
 * ndk.guardrailOff().fetchEvents({ kinds: [1] });
 *
 * // Disable specific guardrail for one call
 * ndk.guardrailOff('fetch-events-usage').fetchEvents({ kinds: [1] });
 *
 * // Disable multiple guardrails for one call
 * ndk.guardrailOff(['fetch-events-usage', 'filter-large-limit'])
 *    .fetchEvents({ kinds: [1], limit: 5000 });
 *
 * // Next call has guardrails re-enabled automatically
 * ndk.fetchEvents({ kinds: [1] }); // Guardrails active again
 * ```
 *
 * @example Hook usage in core code
 * ```typescript
 * // Clean, type-safe hook calls
 * this.aiGuardrails.ndkInstantiated(this);
 * this.aiGuardrails.eventReceived(event, relay);
 * ```
 */

/**
 * Central guardrails manager.
 * Provides both inline validation methods and hook methods for observational checks.
 */
declare class AIGuardrails {
    private enabled;
    private skipSet;
    private extensions;
    private _nextCallDisabled;
    private _replyEvents;
    private _fetchEventsCount;
    private _subscribeCount;
    constructor(mode?: AIGuardrailsMode);
    /**
     * Register an extension namespace with custom guardrail hooks.
     * This allows external packages to add their own guardrails.
     *
     * @example
     * ```typescript
     * // In NDKSvelte package:
     * ndk.aiGuardrails.register('ndkSvelte', {
     *   constructing: (params) => {
     *     if (!params.session) {
     *       warn('ndksvelte-no-session', 'NDKSvelte instantiated without session parameter...');
     *     }
     *   }
     * });
     *
     * // In NDKSvelte constructor:
     * this.ndk.aiGuardrails?.ndkSvelte?.constructing(params);
     * ```
     */
    register(namespace: string, hooks: any): void;
    /**
     * Set the guardrails mode.
     */
    setMode(mode: AIGuardrailsMode): void;
    /**
     * Check if guardrails are enabled at all.
     */
    isEnabled(): boolean;
    /**
     * Check if a specific guardrail check should run.
     */
    shouldCheck(id: string): boolean;
    /**
     * Disable a specific guardrail check.
     */
    skip(id: string): void;
    /**
     * Re-enable a specific guardrail check.
     */
    enable(id: string): void;
    /**
     * Get all currently skipped guardrails.
     */
    getSkipped(): string[];
    /**
     * Capture the current _nextCallDisabled set and clear it atomically.
     * This is used by hook methods to handle one-time guardrail disabling.
     */
    captureAndClearNextCallDisabled(): Set<string> | "all" | null;
    /**
     * Increment fetchEvents call counter for ratio tracking.
     */
    incrementFetchEventsCount(): void;
    /**
     * Increment subscribe call counter for ratio tracking.
     */
    incrementSubscribeCount(): void;
    /**
     * Check if fetchEvents usage ratio exceeds the threshold.
     * Returns true if more than 50% of calls are fetchEvents AND total calls > 6.
     */
    shouldWarnAboutFetchEventsRatio(): boolean;
    /**
     * Throw an error if the check should run.
     * Also logs to console.error in case the throw gets swallowed.
     * @param canDisable - If false, this is a fatal error that cannot be disabled (default: true)
     */
    error(id: string, message: string, hint?: string, canDisable?: boolean): never | undefined;
    /**
     * Throw a warning if the check should run.
     * Also logs to console.error in case the throw gets swallowed.
     * Warnings can always be disabled.
     */
    warn(id: string, message: string, hint?: string): never | undefined;
    /**
     * Format a guardrail message with helpful metadata.
     */
    private formatMessage;
    /**
     * Called when NDK instance is created.
     * Checks for cache presence and other initialization concerns.
     */
    ndkInstantiated(ndk: NDK): void;
    /**
     * NDK-related guardrails
     */
    ndk: {
        /**
         * Called when fetchEvents is about to be called
         */
        fetchingEvents: (filters: any, opts?: any) => void;
    };
    /**
     * Event-related guardrails
     */
    event: {
        /**
         * Called when an event is about to be signed
         */
        signing: (event: NDKEvent) => void;
        /**
         * Called before an event is published
         */
        publishing: (event: NDKEvent) => void;
        /**
         * Called when an event is received from a relay
         */
        received: (_event: NDKEvent, _relay: NDKRelay) => void;
        /**
         * Called when a reply event is being created via .reply()
         * This allows guardrails to track legitimate reply events
         */
        creatingReply: (event: NDKEvent) => void;
    };
    /**
     * Subscription-related guardrails
     */
    subscription: {
        /**
         * Called when a subscription is created
         */
        created: (_filters: any[], _opts?: any) => void;
    };
    /**
     * Relay-related guardrails
     */
    relay: {
        /**
         * Called when a relay connection is established
         */
        connected: (_relay: NDKRelay) => void;
    };
}

type NDKPaymentConfirmationLN = {
    preimage: string;
};
type LNPaymentRequest = string;
type LnPaymentInfo = {
    pr: LNPaymentRequest;
};
type NDKLUD18ServicePayerData = Partial<{
    name: {
        mandatory: boolean;
    };
    pubkey: {
        mandatory: boolean;
    };
    identifier: {
        mandatory: boolean;
    };
    email: {
        mandatory: boolean;
    };
    auth: {
        mandatory: boolean;
        k1: string;
    };
}> & Record<string, unknown>;
type NDKLnUrlData = {
    tag: string;
    callback: string;
    minSendable: number;
    maxSendable: number;
    metadata: string;
    payerData?: NDKLUD18ServicePayerData;
    commentAllowed?: number;
    /**
     * Pubkey of the zapper that should publish zap receipts for this user
     */
    nostrPubkey?: Hexpubkey;
    allowsNostr?: boolean;
};

type NDKCacheEntry<T> = T & {
    cachedAt?: number;
};
/**
 * Cache module definition for packages to extend the cache with their own data structures.
 * Packages define their schemas, indexes, and migrations.
 */
interface CacheModuleDefinition {
    /**
     * Unique namespace for this module (e.g., "messages", "wallet", "sync")
     */
    namespace: string;
    /**
     * Current version of this module's schema
     */
    version: number;
    /**
     * Collection definitions for this module
     */
    collections: {
        [name: string]: {
            /**
             * Primary key field name
             */
            primaryKey: string;
            /**
             * Fields to create indexes on for efficient querying
             */
            indexes?: string[];
            /**
             * Optional schema definition (for validation or TypeScript generation)
             */
            schema?: Record<string, any>;
            /**
             * Compound indexes for multi-field queries
             */
            compoundIndexes?: Array<string[]>;
        };
    };
    /**
     * Migration functions keyed by version number
     * Version 1 is the initial setup, 2+ are upgrades
     */
    migrations: {
        [version: number]: (adapter: CacheModuleMigrationContext) => Promise<void>;
    };
}
/**
 * Migration context passed to module migration functions
 */
interface CacheModuleMigrationContext {
    /**
     * Get a collection by name within the module's namespace
     */
    getCollection(name: string): Promise<CacheModuleCollection<any>>;
    /**
     * Create a new collection
     */
    createCollection(name: string, definition: CacheModuleDefinition["collections"][string]): Promise<void>;
    /**
     * Delete a collection
     */
    deleteCollection(name: string): Promise<void>;
    /**
     * Add an index to a collection
     */
    addIndex(collection: string, field: string | string[]): Promise<void>;
    /**
     * Current version being migrated from
     */
    fromVersion: number;
    /**
     * Target version being migrated to
     */
    toVersion: number;
}
/**
 * Collection interface for module data access
 */
interface CacheModuleCollection<T> {
    /**
     * Get an item by its primary key
     */
    get(id: string): Promise<T | null>;
    /**
     * Get multiple items by their primary keys
     */
    getMany(ids: string[]): Promise<T[]>;
    /**
     * Save an item (upsert)
     */
    save(item: T): Promise<void>;
    /**
     * Save multiple items (bulk upsert)
     */
    saveMany(items: T[]): Promise<void>;
    /**
     * Delete an item by its primary key
     */
    delete(id: string): Promise<void>;
    /**
     * Delete multiple items by their primary keys
     */
    deleteMany(ids: string[]): Promise<void>;
    /**
     * Query items by a single field
     */
    findBy(field: string, value: any): Promise<T[]>;
    /**
     * Query items with multiple conditions
     */
    where(conditions: Record<string, any>): Promise<T[]>;
    /**
     * Get all items in the collection
     */
    all(): Promise<T[]>;
    /**
     * Count items matching conditions
     */
    count(conditions?: Record<string, any>): Promise<number>;
    /**
     * Clear all items from the collection
     */
    clear(): Promise<void>;
}
interface NDKCacheAdapter {
    /**
     * Whether this cache adapter is expected to be fast.
     * If this is true, the cache will be queried before the relays.
     * When this is false, the cache will be queried in addition to the relays.
     */
    locking: boolean;
    /**
     * Weather the cache is ready.
     */
    ready?: boolean;
    initializeAsync?(ndk: NDK): Promise<void>;
    initialize?(ndk: NDK): void;
    /**
     * Either synchronously or asynchronously queries the cache.
     *
     * Cache adapters that return values synchronously should return an array of events.
     * Asynchronous cache adapters should call the subscription.eventReceived method for each event.
     */
    query(subscription: NDKSubscription): NDKEvent[] | Promise<NDKEvent[]>;
    setEvent(event: NDKEvent, filters: NDKFilter[], relay?: NDKRelay): Promise<void>;
    /**
     * Called when we receive a duplicate event from a relay.
     * This associates the relay with an existing cached event without re-processing the event data.
     * @param event - The duplicate event received.
     * @param relay - The relay that sent the duplicate event.
     */
    setEventDup?(event: NDKEvent, relay: NDKRelay): Promise<void> | void;
    /**
     * Called when an event is deleted by the client.
     * Cache adapters should remove the event from their cache.
     * @param eventIds - The ids of the events that were deleted.
     */
    deleteEventIds?(eventIds: NDKEventId[]): Promise<void>;
    /**
     * Fetches a profile from the cache synchronously.
     * @param pubkey - The pubkey of the profile to fetch.
     * @returns The profile, or null if it is not in the cache.
     */
    fetchProfileSync?(pubkey: Hexpubkey): NDKCacheEntry<NDKUserProfile> | null;
    /**
     * Retrieve all profiles from the cache synchronously.
     * @returns A map of pubkeys to profiles.
     */
    getAllProfilesSync?(): Map<Hexpubkey, NDKCacheEntry<NDKUserProfile>>;
    /**
     * Special purpose
     */
    fetchProfile?(pubkey: Hexpubkey): Promise<NDKCacheEntry<NDKUserProfile> | null>;
    saveProfile?(pubkey: Hexpubkey, profile: NDKUserProfile): void | Promise<void>;
    /**
     * Fetches profiles that match the given filter.
     * @param filter - Either a filter function or a filter descriptor object
     * @returns NDKUserProfiles that match the filter.
     * @example
     * // Using a filter function
     * const searchFunc = (pubkey, profile) => profile.name.toLowerCase().includes("alice");
     * const allAliceProfiles = await cache.getProfiles(searchFunc);
     *
     * @example
     * // Using a filter descriptor (supported by some cache adapters like cache-sqlite-wasm)
     * const aliceProfiles = await cache.getProfiles({ field: 'name', contains: 'alice' });
     * // Or search multiple fields
     * const aliceProfiles = await cache.getProfiles({ fields: ['name', 'displayName'], contains: 'alice' });
     */
    getProfiles?: (filter: ((pubkey: Hexpubkey, profile: NDKUserProfile) => boolean) | {
        field?: string;
        fields?: string[];
        contains: string;
    }) => Promise<Map<Hexpubkey, NDKUserProfile> | undefined>;
    loadNip05?(nip05: string, maxAgeForMissing?: number): Promise<ProfilePointer | null | "missing">;
    saveNip05?(nip05: string, profile: ProfilePointer | null): void;
    /**
     * Fetches a user's LNURL data from the cache.
     * @param pubkey The pubkey of the user to fetch the LNURL data for.
     * @param maxAgeInSecs The maximum age of the data in seconds.
     * @param maxAgeForMissing The maximum age of the data in seconds if it is missing before it returns that it should be refetched.
     * @returns The LNURL data, null if it is not in the cache and under the maxAgeForMissing, or "missing" if it should be refetched.
     */
    loadUsersLNURLDoc?(pubkey: Hexpubkey, maxAgeInSecs?: number, maxAgeForMissing?: number): Promise<NDKLnUrlData | null | "missing">;
    saveUsersLNURLDoc?(pubkey: Hexpubkey, doc: NDKLnUrlData | null): void;
    /**
     * Updates information about the relay.
     */
    updateRelayStatus?(relayUrl: WebSocket["url"], info: NDKCacheRelayInfo): void | Promise<void>;
    /**
     * Fetches information about the relay.
     */
    getRelayStatus?(relayUrl: WebSocket["url"]): NDKCacheRelayInfo | undefined | Promise<NDKCacheRelayInfo | undefined>;
    /**
     * Tracks a publishing event.
     * @param event
     * @param relayUrls List of relays that the event will be published to.
     */
    addUnpublishedEvent?(event: NDKEvent, relayUrls: WebSocket["url"][]): void | Promise<void>;
    /**
     * Fetches all unpublished events.
     */
    getUnpublishedEvents?(): Promise<{
        event: NDKEvent;
        relays?: WebSocket["url"][];
        lastTryAt?: number;
    }[]>;
    /**
     * Removes an unpublished event.
     */
    discardUnpublishedEvent?(eventId: NDKEventId): void | Promise<void>;
    /**
     * Called when the cache is ready.
     */
    onReady?(callback: () => void): void;
    /**
     * Get a decrypted event from the cache by its wrapper ID.
     * @param wrapperId - The ID of the gift-wrapped event (kind 1059).
     * @returns The decrypted rumor event, or null if it doesn't exist.
     */
    getDecryptedEvent?(wrapperId: NDKEventId): NDKEvent | null | Promise<NDKEvent | null>;
    /**
     * Store a decrypted event in the cache.
     * @param wrapperId - The ID of the gift-wrapped event (kind 1059) to use as the cache key.
     * @param decryptedEvent - The decrypted rumor event to store.
     */
    addDecryptedEvent?(wrapperId: NDKEventId, decryptedEvent: NDKEvent): void | Promise<void>;
    /**
     * Cleans up the cache. This is called when the user logs out.
     */
    clear?(): Promise<void>;
    /**
     * Gets all nutzap states from the cache.
     * @returns A map of event IDs to nutzap states.
     */
    getAllNutzapStates?(): Promise<Map<NDKEventId, NDKNutzapState>>;
    /**
     * Sets the state of a nutzap in the cache.
     * @param id The ID of the nutzap event.
     * @param stateChange The partial state change to apply.
     */
    setNutzapState?(id: NDKEventId, stateChange: Partial<NDKNutzapState>): Promise<void>;
    /**
     * Generic key-value cache storage for packages.
     * Packages should namespace their keys (e.g., "wallet:mint:info:https://mint.url").
     * @param namespace The namespace for the data (e.g., "wallet", "sync")
     * @param key The key within the namespace
     * @param maxAgeInSecs Maximum age of cached data in seconds (optional)
     * @returns The cached data, or undefined if not cached or expired
     */
    getCacheData?<T>(namespace: string, key: string, maxAgeInSecs?: number): Promise<T | undefined>;
    /**
     * Generic key-value cache storage for packages.
     * @param namespace The namespace for the data (e.g., "wallet", "sync")
     * @param key The key within the namespace
     * @param data The data to cache
     */
    setCacheData?<T>(namespace: string, key: string, data: T): Promise<void>;
    /**
     * Cache module support - Register a module with its schema and migrations
     * @param module Module definition with schema, indexes, and migrations
     * @returns Promise that resolves when the module is registered and migrations are complete
     */
    registerModule?(module: CacheModuleDefinition): Promise<void>;
    /**
     * Cache module support - Get a collection from a registered module
     * @param namespace Module namespace
     * @param collection Collection name within the module
     * @returns Collection interface for data operations
     */
    getModuleCollection?<T>(namespace: string, collection: string): Promise<CacheModuleCollection<T>>;
}
/**
 * Relay metadata and statistics stored in cache.
 *
 * This type supports both core connection tracking and extensible package-specific metadata.
 * Packages can store custom data using the metadata field with namespacing.
 *
 * @example
 * ```typescript
 * // Core connection tracking
 * await cache.updateRelayStatus(url, {
 *   lastConnectedAt: Date.now(),
 *   consecutiveFailures: 0
 * });
 *
 * // Package-specific metadata (sync package)
 * await cache.updateRelayStatus(url, {
 *   metadata: {
 *     sync: {
 *       supportsNegentropy: false,
 *       lastChecked: Date.now()
 *     }
 *   }
 * });
 *
 * // Package-specific metadata (auth/rate limiting)
 * await cache.updateRelayStatus(url, {
 *   metadata: {
 *     auth: {
 *       token: 'AUTH_TOKEN_HERE',
 *       expiresAt: Date.now() + 3600000
 *     },
 *     rateLimit: {
 *       requestCount: 42,
 *       windowStart: Date.now(),
 *       maxPerWindow: 100
 *     }
 *   }
 * });
 *
 * // NIP-11 caching
 * await cache.updateRelayStatus(url, {
 *   nip11: {
 *     data: relayInfo,
 *     fetchedAt: Date.now()
 *   }
 * });
 * ```
 */
type NDKCacheRelayInfo = {
    /**
     * Timestamp of last successful connection
     */
    lastConnectedAt?: number;
    /**
     * Don't attempt connection before this timestamp
     */
    dontConnectBefore?: number;
    /**
     * Number of consecutive connection failures
     */
    consecutiveFailures?: number;
    /**
     * Timestamp of last connection failure
     */
    lastFailureAt?: number;
    /**
     * Cached NIP-11 relay information document
     */
    nip11?: {
        data: NDKRelayInformation;
        fetchedAt: number;
    };
    /**
     * Package-specific metadata (namespaced).
     *
     * Packages should use their package name as the namespace key.
     *
     * @example
     * ```typescript
     * metadata: {
     *   sync: { supportsNegentropy: false, lastChecked: 1234567890 },
     *   auth: { token: 'abc123', expiresAt: 1234567890 },
     *   rateLimit: { requestCount: 42, windowStart: 1234567890, maxPerWindow: 100 }
     * }
     * ```
     */
    metadata?: Record<string, Record<string, unknown>>;
};

type OutboxItemType = "user" | "kind";
/**
 * Tracks outbox scoring of an item. An item can be any of:
 *
 *  -  A user
 *  -  A tag
 */
declare class OutboxItem {
    /**
     * Type of item
     */
    type: OutboxItemType;
    /**
     * The relay URLs that are of interest to this item
     */
    relayUrlScores: Map<WebSocket["url"], number>;
    readRelays: Set<WebSocket["url"]>;
    writeRelays: Set<WebSocket["url"]>;
    constructor(type: OutboxItemType);
}
/**
 * The responsibility of this class is to track relay:outbox-item associations
 * so that we can intelligently choose which relays to query for which items.
 *
 * A single instance of this class should be shared across all subscriptions within
 * an NDK instance.
 *
 * TODO: The state of this tracker needs to be added to cache adapters so that we
 * can rehydrate-it when a cache is present.
 */
declare class OutboxTracker extends EventEmitter {
    data: LRUCache<Hexpubkey, OutboxItem>;
    private ndk;
    private debug;
    constructor(ndk: NDK);
    /**
     * Adds a list of users to the tracker.
     * @param items
     * @param skipCache
     */
    trackUsers(items: NDKUser[] | Hexpubkey[], skipCache?: boolean): Promise<void[]>;
    /**
     *
     * @param key
     * @param score
     */
    track(item: NDKUser | Hexpubkey, type?: OutboxItemType, _skipCache?: boolean): OutboxItem;
}

type Proof$1 = {
    /**
     * Keyset id, used to link proofs to a mint an its MintKeys.
     */
    id: string;
    /**
     * Amount denominated in Satoshis. Has to match the amount of the mints signing key.
     */
    amount: number;
    /**
     * The initial secret that was (randomly) chosen for the creation of this proof.
     */
    secret: string;
    /**
     * The unblinded signature for this secret, signed by the mints private key.
     */
    C: string;
};

declare enum NutzapValidationCode {
    NO_PROOFS = "NO_PROOFS",
    INVALID_PROOF_COUNT = "INVALID_PROOF_COUNT",
    MULTIPLE_RECIPIENTS = "MULTIPLE_RECIPIENTS",
    NO_RECIPIENT = "NO_RECIPIENT",
    MULTIPLE_MINTS = "MULTIPLE_MINTS",
    NO_MINT = "NO_MINT",
    MULTIPLE_EVENT_TAGS = "MULTIPLE_EVENT_TAGS",
    MALFORMED_PROOF_SECRET = "MALFORMED_PROOF_SECRET",
    MISSING_EVENT_TAG_IN_PROOF = "MISSING_EVENT_TAG_IN_PROOF",
    MISMATCHED_EVENT_TAG_IN_PROOF = "MISMATCHED_EVENT_TAG_IN_PROOF",
    MISSING_SENDER_TAG_IN_PROOF = "MISSING_SENDER_TAG_IN_PROOF",
    MISMATCHED_SENDER_TAG_IN_PROOF = "MISMATCHED_SENDER_TAG_IN_PROOF",
    NO_EVENT_TAG_IN_EVENT = "NO_EVENT_TAG_IN_EVENT"
}
declare enum NutzapValidationSeverity {
    ERROR = "ERROR",
    WARNING = "WARNING"
}
type NutzapValidationIssue = {
    code: NutzapValidationCode;
    severity: NutzapValidationSeverity;
    message: string;
    proofIndex?: number;
};
type NutzapValidationResult = {
    valid: boolean;
    issues: NutzapValidationIssue[];
};

/**
 * Represents a NIP-61 nutzap
 */
declare class NDKNutzap extends NDKEvent {
    private debug;
    private _proofs;
    static kind: NDKKind;
    static kinds: NDKKind[];
    constructor(ndk?: NDK, event?: NostrEvent | NDKEvent);
    static from(event: NDKEvent): NDKNutzap | undefined;
    set comment(comment: string | undefined);
    get comment(): string;
    set proofs(proofs: Proof$1[]);
    get proofs(): Proof$1[];
    get rawP2pk(): string | undefined;
    /**
     * Gets the p2pk pubkey that is embedded in the first proof.
     *
     * Note that this returns a nostr pubkey, not a cashu pubkey (no "02" prefix)
     */
    get p2pk(): string | undefined;
    /**
     * Get the mint where this nutzap proofs exist
     */
    get mint(): string;
    set mint(value: string);
    get unit(): string;
    set unit(value: string | undefined);
    get amount(): number;
    sender: NDKUser;
    /**
     * Set the target of the nutzap
     * @param target The target of the nutzap (a user or an event)
     */
    set target(target: NDKEvent | NDKUser);
    set recipientPubkey(pubkey: Hexpubkey);
    get recipientPubkey(): Hexpubkey;
    get recipient(): NDKUser;
    toNostrEvent(): Promise<NostrEvent>;
    /**
     * Validates that the nutzap conforms to NIP-61
     * @deprecated Use validateNIP61() instead for detailed validation results
     */
    get isValid(): boolean;
    /**
     * Performs comprehensive validation of the nutzap according to NIP-61.
     * Returns detailed validation results including errors and warnings.
     *
     * Errors make the nutzap invalid, warnings are recommendations for best practices.
     */
    validateNIP61(): NutzapValidationResult;
}

/**
 * Provides information that should be used to send a NIP-61 nutzap.
 * mints: URLs of the mints that can be used.
 * relays: URLs of the relays where nutzap must be published
 * p2pk: Optional pubkey to use for P2PK lock
 */
type CashuPaymentInfo = {
    /**
     * Mints that must be used for the payment
     */
    mints?: string[];
    /**
     * Relays where nutzap must be published
     */
    relays?: string[];
    /**
     * Optional pubkey to use for P2PK lock
     */
    p2pk?: string;
    /**
     * Tags to include in the proof secrets (e.g., [["e", "event-id"], ["P", "sender-pubkey"]])
     * These tags will be added to the P2PK lock structure for replay protection and sender verification.
     */
    proofTags?: [string, string][];
    /**
     * Intramint fallback allowed:
     *
     * When set to true, if cross-mint payments fail, we will
     * fallback to sending an intra-mint payment.
     */
    allowIntramintFallback?: boolean;
};
/**
 * This is what a wallet implementing Cashu payments should provide back
 * when a payment has been requested.
 */
type NDKPaymentConfirmationCashu = {
    /**
     * Proof of the payment
     */
    proofs: Proof$1[];
    /**
     * Mint
     */
    mint: string;
};

type NDKZapDetails<T> = T & {
    /**
     * Target of the zap
     */
    target: NDKEvent | NDKUser;
    /**
     * Comment for the zap
     */
    comment?: string;
    /**
     * Tags to add to the zap
     */
    tags?: NDKTag[];
    /**
     * Pubkey of the user to zap to
     */
    recipientPubkey: string;
    /**
     * Amount of the payment
     */
    amount: number;
    /**
     * Unit of the payment (e.g. msat)
     */
    unit: string;
    /**
     * Description of the payment for the sender's record
     */
    paymentDescription?: string;
    /**
     * If this payment is for a nip57 zap, this will contain the zap request.
     */
    nip57ZapRequest?: NDKEvent;
    /**
     * When set to true, when a pubkey is not zappable, we will
     * automatically fallback to using NIP-61.
     *
     * Every pubkey must be able to receive money.
     *
     * @default false
     */
    nutzapAsFallback?: boolean;
};
type NDKPaymentConfirmation = NDKPaymentConfirmationLN | NDKNutzap;
type NDKZapSplit = {
    pubkey: string;
    amount: number;
};
type NDKZapMethod = "nip57" | "nip61";
type NDKLnLudData = {
    lud06?: string;
    lud16?: string;
};
type NDKZapMethodInfo = NDKLnLudData | CashuPaymentInfo;
type LnPayCb = (payment: NDKZapDetails<LnPaymentInfo>) => Promise<NDKPaymentConfirmationLN | undefined>;
type CashuPayCb = (payment: NDKZapDetails<CashuPaymentInfo>, onLnInvoice?: (pr: string) => void) => Promise<NDKPaymentConfirmationCashu | undefined>;

type QueueItem<T> = {
    /**
     * Deterministic id of the item
     */
    id: string;
    /**
     * A function to process the item
     * @returns
     */
    func: () => Promise<T>;
};
declare class Queue<T> {
    private queue;
    private maxConcurrency;
    private processing;
    private promises;
    constructor(_name: string, maxConcurrency: number);
    add(item: QueueItem<T>): Promise<T>;
    private process;
    clear(): void;
    clearProcessing(): void;
    clearAll(): void;
    length(): number;
}

type NDKValidationRatioFn = (relay: NDKRelay, validatedCount: number, nonValidatedCount: number) => number;
type NDKNetDebug = (msg: string, relay: NDKRelay, direction?: "send" | "recv") => void;
/**
 * An interface compatible with ndk-wallet that allows setting multiple handlers and callbacks.
 */
interface NDKWalletInterface {
    lnPay?: LnPayCb;
    cashuPay?: CashuPayCb;
    onPaymentComplete?: (results: Map<NDKZapSplit, NDKPaymentConfirmation | Error | undefined>) => void;
}
interface NDKConstructorParams {
    /**
     * Relays we should explicitly connect to
     */
    explicitRelayUrls?: string[];
    /**
     * When this is set, we always write only to this relays.
     */
    devWriteRelayUrls?: string[];
    /**
     * Outbox relay URLs.
     */
    outboxRelayUrls?: string[];
    /**
     * Enable outbox model (defaults to true)
     */
    enableOutboxModel?: boolean;
    /**
     * Auto-connect to main user's relays. The "main" user is determined
     * by the presence of a signer. Upon connection to the explicit relays,
     * the user's relays will be fetched and connected to if this is set to true.
     * @default true
     */
    autoConnectUserRelays?: boolean;
    /**
     * Signer to use for signing events by default
     */
    signer?: NDKSigner;
    /**
     * Cache adapter to use for caching events
     */
    cacheAdapter?: NDKCacheAdapter;
    /**
     * Debug instance to use
     */
    debug?: debug$1.Debugger;
    /**
     * Provide a caller function to receive all networking traffic from relays
     */
    netDebug?: NDKNetDebug;
    /**
     * Custom filter function to determine if an event should be muted.
     * @param event - The event to check
     * @returns true if the event should be muted
     */
    muteFilter?: (event: NDKEvent) => boolean;
    /**
     * Custom filter function to determine if a relay connection should be allowed.
     * @param relayUrl - The relay URL to check
     * @returns true if the connection should be allowed, false to block it
     */
    relayConnectionFilter?: (relayUrl: string) => boolean;
    /**
     * Client name to add to events' tag
     */
    clientName?: string;
    /**
     * Client nip89 to add to events' tag
     */
    clientNip89?: string;
    /**
     * Default relay-auth policy
     */
    relayAuthDefaultPolicy?: NDKAuthPolicy;
    /**
     * Set a Web Worker for signature verification.
     *
     * @default undefined
     *
     * When provided, signature verification will be processed in a web worker.
     * You should listen for the `event:invalid-sig` event to handle invalid signatures.
     *
     * @example
     * ```typescript
     * const worker = new Worker("path/to/signature-verification.js");
     * ndk.signatureVerificationWorker = worker;
     * ndk.on("event:invalid-sig", (event) => {
     *    console.error("Invalid signature", event);
     * });
     * ```
     */
    signatureVerificationWorker?: Worker | undefined;
    /**
     * The signature verification validation ratio for new relays.
     */
    initialValidationRatio?: number;
    /**
     * The lowest validation ratio any single relay can have.
     * Relays will have a sample of events verified based on this ratio.
     * When using this, you MUST listen for event:invalid-sig events
     * to handle invalid signatures and disconnect from evil relays.
     *
     * @default 0.1
     */
    lowestValidationRatio?: number;
    /**
     * A function that is invoked to calculate the validation ratio for a relay.
     */
    validationRatioFn?: NDKValidationRatioFn;
    /**
     * A custom function to verify event signatures.
     * When provided, this function will be used instead of the default verification logic.
     * This is particularly useful for platforms like React Native where Web Workers are not available.
     *
     * @example
     * ```typescript
     * import { verifySignatureAsync } from "@nostr-dev-kit/mobile";
     *
     * const ndk = new NDK({
     *   signatureVerificationFunction: verifySignatureAsync
     * });
     * ```
     */
    signatureVerificationFunction?: (event: NDKEvent) => Promise<boolean>;
    /**
     * Filter validation mode for subscriptions.
     *
     * @default "validate" - Throws an error when filters contain undefined values
     * "fix" - Automatically removes undefined values from filters
     * "ignore" - Skip validation entirely (legacy behavior)
     */
    filterValidationMode?: "validate" | "fix" | "ignore";
    /**
     * ⚠️ STRONGLY RECOMMENDED: Enable AI Guardrails during development
     *
     * AI Guardrails catch 90% of common mistakes before they cause silent failures:
     * - Using bech32 (npub/note1) in filter arrays instead of hex
     * - Missing required fields on events (kind, content, etc.)
     * - Invalid tag formats and duplicate tags
     * - Performance anti-patterns (fetchEvents abuse, no cache adapter)
     * - Wrong data types (milliseconds vs seconds for created_at)
     *
     * When enabled, you'll get clear, actionable error messages instead of silent failures.
     *
     * @default false - Guardrails are disabled (zero performance impact)
     *
     * @example RECOMMENDED: Enable during development
     * ```typescript
     * const ndk = new NDK({
     *   explicitRelayUrls: ['wss://relay.primal.net'],
     *   aiGuardrails: true  // ⚠️ Enable this!
     * });
     * ```
     *
     * @example Disable in production
     * ```typescript
     * const ndk = new NDK({
     *   aiGuardrails: process.env.NODE_ENV !== 'production'
     * });
     * ```
     *
     * @example Enable with specific checks disabled
     * ```typescript
     * const ndk = new NDK({
     *   aiGuardrails: { skip: new Set(['filter-large-limit']) }
     * });
     * ```
     *
     * @example Programmatic control
     * ```typescript
     * ndk.aiGuardrails.skip('fetch-events-usage');
     * ndk.aiGuardrails.enable('filter-bech32-in-array');
     * ```
     *
     * @see https://github.com/nostr-dev-kit/ndk/tree/master/ndk/src/ai-guardrails
     */
    aiGuardrails?: boolean | {
        skip?: Set<string>;
    };
    /**
     * Optional grace period (in seconds) for future timestamps.
     *
     * When set, subscriptions will automatically discard events where
     * `created_at` is more than this many seconds ahead of the current time.
     * This helps protect against malicious relays sending events with
     * manipulated timestamps.
     *
     * Set to `undefined` (default) to disable this check and accept all events
     * regardless of timestamp.
     *
     * @default undefined
     *
     * @example Reject events more than 5 minutes in the future
     * ```typescript
     * const ndk = new NDK({
     *   explicitRelayUrls: ['wss://relay.primal.net'],
     *   futureTimestampGrace: 300 // 5 minutes
     * });
     * ```
     */
    futureTimestampGrace?: number;
}
interface GetUserParams extends NDKUserParams {
    npub?: string;
    pubkey?: string;
    /**
     * @deprecated Use `pubkey` instead
     */
    hexpubkey?: string;
}
/**
 * Defines handlers that can be passed to `ndk.subscribe` via the `autoStart` parameter
 * to react to subscription lifecycle events.
 */
interface NDKSubscriptionEventHandlers {
    /**
     * Called for each individual event received from relays *after* the initial cache load (if `onEvents` is provided),
     * or for *all* events (including cached ones) if `onEvents` is not provided.
     * @param event The received NDKEvent.
     * @param relay The relay the event was received from (undefined if from cache).
     */
    onEvent?: (event: NDKEvent, relay?: NDKRelay) => void;
    /**
     * Called *once* with an array of all events found synchronously in the cache when the subscription starts.
     * If this handler is provided, `onEvent` will *not* be called for this initial batch of cached events.
     * This is useful for bulk processing or batching UI updates based on the initial cached state.
     * @param events An array of NDKEvents loaded synchronously from the cache.
     */
    onEvents?: (events: NDKEvent[]) => void;
    /**
     * Called when the subscription receives an EOSE (End of Stored Events) marker
     * from all connected relays involved in this subscription request.
     * @param sub The NDKSubscription instance that reached EOSE.
     */
    onEose?: (sub: NDKSubscription) => void;
    /**
     * Called when the subscription is closed.
     * @param sub The NDKSubscription instance that was closed.
     */
    onClose?: (sub: NDKSubscription) => void;
}
/**
 * The NDK class is the main entry point to the library.
 *
 * @emits signer:ready when a signer is ready
 * @emits activeUser:change when the active user changes
 * @emits invalid-signature when an event with an invalid signature is received
 */
declare class NDK extends EventEmitter<{
    "signer:ready": (signer: NDKSigner) => void;
    "signer:required": () => void;
    /**
     * Emitted when the active user changes.
     * This can happen when a signer is set or when activeUser is set directly.
     */
    "activeUser:change": (user: NDKUser | undefined) => void;
    /**
     * Emitted when an event with an invalid signature is received.
     * Includes the relay that provided the invalid signature.
     */
    "event:invalid-sig": (event: NDKEvent, relay?: NDKRelay) => void;
    /**
     * Emitted when an event fails to publish.
     * @param event The event that failed to publish
     * @param error The error that caused the event to fail to publish
     * @param relays The relays that the event was attempted to be published to
     */
    "event:publish-failed": (event: NDKEvent, error: NDKPublishError, relays: WebSocket["url"][]) => void;
}> {
    private _explicitRelayUrls?;
    pool: NDKPool;
    outboxPool?: NDKPool;
    private _signer?;
    private _activeUser?;
    cacheAdapter?: NDKCacheAdapter;
    debug: debug$1.Debugger;
    devWriteRelaySet?: NDKRelaySet;
    outboxTracker?: OutboxTracker;
    muteFilter?: (event: NDKEvent) => boolean;
    relayConnectionFilter?: (relayUrl: string) => boolean;
    clientName?: string;
    clientNip89?: string;
    queuesZapConfig: Queue<NDKLnUrlData | undefined>;
    queuesNip05: Queue<ProfilePointer | null>;
    asyncSigVerification: boolean;
    initialValidationRatio: number;
    lowestValidationRatio: number;
    validationRatioFn?: NDKValidationRatioFn;
    filterValidationMode: "validate" | "fix" | "ignore";
    subManager: NDKSubscriptionManager;
    aiGuardrails: AIGuardrails;
    futureTimestampGrace?: number;
    /**
     * Private storage for the signature verification function
     */
    private _signatureVerificationFunction?;
    /**
     * Private storage for the signature verification worker
     */
    private _signatureVerificationWorker?;
    /**
     * Rolling total of time spent (in ms) performing signature verifications.
     * Users can read this to monitor or display aggregate verification cost.
     */
    signatureVerificationTimeMs: number;
    publishingFailureHandled: boolean;
    pools: NDKPool[];
    /**
     * Default relay-auth policy that will be used when a relay requests authentication,
     * if no other policy is specified for that relay.
     *
     * @example Disconnect from relays that request authentication:
     * ```typescript
     * ndk.relayAuthDefaultPolicy = NDKAuthPolicies.disconnect(ndk.pool);
     * ```
     *
     * @example Sign in to relays that request authentication:
     * ```typescript
     * ndk.relayAuthDefaultPolicy = NDKAuthPolicies.signIn({ndk})
     * ```
     *
     * @example Sign in to relays that request authentication, asking the user for confirmation:
     * ```typescript
     * ndk.relayAuthDefaultPolicy = (relay: NDKRelay) => {
     *     const signIn = NDKAuthPolicies.signIn({ndk});
     *     if (confirm(`Relay ${relay.url} is requesting authentication, do you want to sign in?`)) {
     *        signIn(relay);
     *     }
     * }
     * ```
     */
    relayAuthDefaultPolicy?: NDKAuthPolicy;
    /**
     * Fetch function to use for HTTP requests.
     *
     * @example
     * ```typescript
     * import fetch from "node-fetch";
     *
     * ndk.httpFetch = fetch;
     * ```
     */
    httpFetch: typeof fetch | undefined;
    /**
     * Provide a caller function to receive all networking traffic from relays
     */
    readonly netDebug?: NDKNetDebug;
    autoConnectUserRelays: boolean;
    private _wallet?;
    walletConfig?: NDKWalletInterface;
    constructor(opts?: NDKConstructorParams);
    set explicitRelayUrls(urls: WebSocket["url"][]);
    get explicitRelayUrls(): WebSocket["url"][];
    /**
     * Set a Web Worker for signature verification.
     *
     * This method initializes the worker and sets the asyncSigVerification flag.
     * The actual verification is handled by the verifySignatureAsync function in signature.ts,
     * which will use the worker if available.
     */
    set signatureVerificationWorker(worker: Worker | undefined);
    /**
     * Set a custom signature verification function.
     *
     * This method is particularly useful for platforms that don't support Web Workers,
     * such as React Native.
     *
     * When a function is provided, it will be used for signature verification
     * instead of the default worker-based verification. This enables signature
     * verification on platforms where Web Workers are not available.
     *
     * @example
     * ```typescript
     * import { verifySignatureAsync } from "@nostr-dev-kit/mobile";
     *
     * ndk.signatureVerificationFunction = verifySignatureAsync;
     * ```
     */
    set signatureVerificationFunction(fn: ((event: NDKEvent) => Promise<boolean>) | undefined);
    /**
     * Get the custom signature verification function
     */
    get signatureVerificationFunction(): ((event: NDKEvent) => Promise<boolean>) | undefined;
    /**
     * Adds an explicit relay to the pool.
     * @param url
     * @param relayAuthPolicy Authentication policy to use if different from the default
     * @param connect Whether to connect to the relay automatically
     * @returns
     */
    addExplicitRelay(urlOrRelay: string | NDKRelay, relayAuthPolicy?: NDKAuthPolicy, connect?: boolean): NDKRelay;
    toJSON(): string;
    get activeUser(): NDKUser | undefined;
    /**
     * Sets the active user for this NDK instance, typically this will be
     * called when assigning a signer to the NDK instance.
     *
     * This function will automatically connect to the user's relays if
     * `autoConnectUserRelays` is set to true.
     */
    set activeUser(user: NDKUser | undefined);
    get signer(): NDKSigner | undefined;
    set signer(newSigner: NDKSigner | undefined);
    /**
     * Connect to relays with optional timeout.
     * If the timeout is reached, the connection will be continued to be established in the background.
     */
    connect(timeoutMs?: number): Promise<void>;
    /**
     * Centralized method to report an invalid signature, identifying the relay that provided it.
     * A single invalid signature means the relay is considered malicious.
     * All invalid signature detections (synchronous or asynchronous) should delegate to this method.
     *
     * @param event The event with an invalid signature
     * @param relay The relay that provided the invalid signature
     */
    reportInvalidSignature(event: NDKEvent, relay?: NDKRelay): void;
    /**
     * Default function to calculate validation ratio based on historical validation results.
     * The more events validated successfully, the lower the ratio goes (down to the minimum).
     */
    private defaultValidationRatioFn;
    /**
     * Get a NDKUser object
     *
     * @deprecated Use `fetchUser` instead - this method will be removed in the next major version
     * @param opts - User parameters object or a string (npub, nprofile, or hex pubkey)
     * @returns NDKUser instance
     *
     * @example
     * ```typescript
     * // Using parameters object
     * const user1 = ndk.getUser({ pubkey: "hex..." });
     *
     * // Using npub string
     * const user2 = ndk.getUser("npub1...");
     *
     * // Using nprofile string (includes relay hints)
     * const user3 = ndk.getUser("nprofile1...");
     *
     * // Using hex pubkey directly
     * const user4 = ndk.getUser("deadbeef...");
     * ```
     */
    getUser(opts: GetUserParams | string): NDKUser;
    /**
     * Get a NDKUser from a NIP05
     * @deprecated Use `fetchUser` instead - this method will be removed in the next major version
     * @param nip05 NIP-05 ID
     * @param skipCache Skip cache
     * @returns
     */
    getUserFromNip05(nip05: string, skipCache?: boolean): Promise<NDKUser | undefined>;
    /**
     * Fetch a NDKUser from a string identifier
     *
     * Supports multiple input formats:
     * - NIP-05 identifiers (e.g., "pablo@test.com" or "test.com")
     * - npub (NIP-19 encoded public key)
     * - nprofile (NIP-19 encoded profile with optional relay hints)
     * - Hex public key
     *
     * @param input - String identifier for the user (NIP-05, npub, nprofile, or hex pubkey)
     * @param skipCache - Skip cache when resolving NIP-05 (only applies to NIP-05 lookups)
     * @returns Promise resolving to NDKUser or undefined if not found
     *
     * @example
     * ```typescript
     * // Using NIP-05
     * const user1 = await ndk.fetchUser("pablo@test.com");
     * const user2 = await ndk.fetchUser("test.com"); // defaults to _@test.com
     *
     * // Using npub
     * const user3 = await ndk.fetchUser("npub1...");
     *
     * // Using nprofile (includes relay hints)
     * const user4 = await ndk.fetchUser("nprofile1...");
     *
     * // Using hex pubkey
     * const user5 = await ndk.fetchUser("deadbeef...");
     * ```
     */
    fetchUser(input: string, skipCache?: boolean): Promise<NDKUser | undefined>;
    /**
     * Creates and starts a new subscription.
     *
     * Subscriptions automatically start unless `autoStart` is set to `false`.
     * You can control automatic closing on EOSE via `opts.closeOnEose`.
     *
     * @param filters - A single NDKFilter object or an array of filters.
     * @param opts - Optional NDKSubscriptionOptions to customize behavior (e.g., caching, grouping).
     * @param handlers - Optional handlers for subscription events. Passing handlers is the preferred method of using ndk.subscribe.
     *   - `onEvent`: Called for each event received.
     *  - `onEvents`: Called once with an array of events when the subscription starts (from the cache).
     *  - `onEose`: Called when the subscription receives EOSE.
     *  For backwards compatibility, this third parameter also accepts a relaySet, the relaySet should be passed via `opts.relaySet`.
     *
     * @param _autoStart - For backwards compatibility, this can be a boolean indicating whether to start the subscription immediately.
     *  This parameter is deprecated and will be removed in a future version.
     *   - `false`: Creates the subscription but does not start it (call `subscription.start()` manually).
     * @returns The created NDKSubscription instance.
     *
     * @example Basic subscription
     * ```typescript
     * const sub = ndk.subscribe(
     *   { kinds: [1], authors: [pubkey] },
     *   {
     *     onEvent: (event) => console.log("Kind 1 event:", event.content)
     *   }
     * );
     * ```
     *
     * @example Subscription with options and direct handlers
     * ```typescript
     * const sub = ndk.subscribe(
     *   { kinds: [0], authors: [pubkey] },
     *   {
     *     closeOnEose: true,
     *     cacheUsage: NDKSubscriptionCacheUsage.PARALLEL,
     *     onEvents: (events) => console.log(`Got ${events.length} profile events from cache:`, events[0].content),
     *     onEvent: (event) => console.log("Got profile update from relay:", event.content),
     *     onEose: () => console.log("Profile subscription finished.")
     *   }
     * );
     * ```
     *
     * @since 2.13.0 `relaySet` parameter removed; pass `relaySet` or `relayUrls` via `opts`.
     */
    subscribe(filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, autoStartOrRelaySet?: NDKRelaySet | boolean | NDKSubscriptionEventHandlers, _autoStart?: boolean): NDKSubscription;
    /**
     * Attempts to fetch an event from a tag, following relay hints and
     * other best practices.
     * @param tag Tag to fetch the event from
     * @param originalEvent Event where the tag came from
     * @param subOpts Subscription options to use when fetching the event
     * @param fallback Fallback options to use when the hint relay doesn't respond
     * @returns
     */
    fetchEventFromTag: (tag: NDKTag, originalEvent: NDKEvent, subOpts?: NDKSubscriptionOptions | undefined, fallback?: NDKFetchFallbackOptions | undefined) => Promise<NDKEvent | null>;
    /**
     * Fetch an event from the cache synchronously.
     * @param idOrFilter event id in bech32 format or filter
     * @returns events from the cache or null if the cache is empty
     */
    fetchEventSync(idOrFilter: string | NDKFilter[]): NDKEvent[] | null;
    /**
     * Fetch a single event.
     *
     * @param idOrFilter event id in bech32 format or filter
     * @param opts subscription options
     * @param relaySetOrRelay explicit relay set to use
     */
    fetchEvent(idOrFilter: string | NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, relaySetOrRelay?: NDKRelaySet | NDKRelay): Promise<NDKEvent | null>;
    /**
     * Fetch events
     */
    fetchEvents(filters: NDKFilter | NDKFilter[], opts?: NDKSubscriptionOptions, relaySet?: NDKRelaySet): Promise<Set<NDKEvent>>;
    /**
     * Count events matching the given filters using NIP-45.
     *
     * This method queries multiple relays and aggregates their COUNT responses.
     * When relays return HyperLogLog (HLL) data, it uses the HLL algorithm to
     * provide accurate cardinality estimation without double-counting events
     * that appear on multiple relays.
     *
     * @param filters - The filters to count events for
     * @param opts - Optional count options (timeout, custom id)
     * @param relaySet - Optional relay set to use for the count request
     * @returns An aggregated count result with the best estimate and per-relay results
     *
     * @example Basic count
     * ```typescript
     * const result = await ndk.count([{ kinds: [1], authors: [pubkey] }]);
     * console.log(`Found approximately ${result.count} events`);
     * ```
     *
     * @example Count with specific relays
     * ```typescript
     * const relaySet = NDKRelaySet.fromRelayUrls(['wss://relay1.com', 'wss://relay2.com'], ndk);
     * const result = await ndk.count([{ kinds: [7], "#e": [eventId] }], {}, relaySet);
     * console.log(`Approximately ${result.count} reactions`);
     * ```
     *
     * @example Using HLL data for further analysis
     * ```typescript
     * const result = await ndk.count([{ kinds: [3] }]);
     * if (result.mergedHll) {
     *   console.log('HLL data available for further merging');
     * }
     * ```
     */
    count(filters: NDKFilter | NDKFilter[], opts?: NDKCountOptions, relaySet?: NDKRelaySet): Promise<NDKAggregatedCountResult>;
    /**
     * Ensures that a signer is available to sign an event.
     */
    assertSigner(): void;
    getEntity: (entity: string) => NDKUser | nip19.DecodedNevent | nip19.DecodedNaddr | nip19.DecodedNsec | nip19.DecodedNote | null;
    /**
     * Temporarily disable AI guardrails for the next method call.
     *
     * @param ids - Optional guardrail IDs to disable. If omitted, all guardrails are disabled for the next call.
     *              Can be a single string or an array of strings.
     * @returns This NDK instance for method chaining
     *
     * @example Disable all guardrails for one call
     * ```typescript
     * ndk.guardrailOff().fetchEvents({ kinds: [1] });
     * ```
     *
     * @example Disable specific guardrail
     * ```typescript
     * ndk.guardrailOff('fetch-events-usage').fetchEvents({ kinds: [1] });
     * ```
     *
     * @example Disable multiple guardrails
     * ```typescript
     * ndk.guardrailOff(['fetch-events-usage', 'filter-large-limit']).fetchEvents({ kinds: [1], limit: 5000 });
     * ```
     */
    guardrailOff(ids?: string | string[]): this;
    set wallet(wallet: NDKWalletInterface | undefined);
    get wallet(): NDKWalletInterface | undefined;
}

type ContentTag = {
    tags: NDKTag[];
    content: string;
};

/**
 * NIP-73 entity types
 */
type NIP73EntityType = "url" | "hashtag" | "geohash" | "isbn" | "podcast:guid" | "podcast:item:guid" | "podcast:publisher:guid" | "isan" | "doi";

type NDKEventSerialized = string;

type NDKEventId = string;
type NDKTag = string[];
type ContentTaggingOptions = {
    skipContentTagging?: boolean;
    pTagOnQTags?: boolean;
    pTagOnATags?: boolean;
    pTags?: boolean;
    copyPTagsFromTarget?: boolean;
    filters?: {
        includeTypes?: Array<"npub" | "nprofile" | "note" | "nevent" | "naddr" | "hashtag">;
        excludeTypes?: Array<"npub" | "nprofile" | "note" | "nevent" | "naddr" | "hashtag">;
    };
};
type NostrEvent = {
    created_at: number;
    content: string;
    tags: NDKTag[];
    kind?: NDKKind | number;
    pubkey: string;
    id?: string;
    sig?: string;
};
/**
 * A finalized event
 */
type NDKRawEvent = {
    created_at: number;
    content: string;
    tags: NDKTag[];
    kind: NDKKind | number;
    pubkey: string;
    id: string;
    sig: string;
};
/**
 * NDKEvent is the basic building block of NDK; most things
 * you do with NDK will revolve around writing or consuming NDKEvents.
 */
declare class NDKEvent extends EventEmitter {
    ndk?: NDK;
    created_at?: number;
    content: string;
    tags: NDKTag[];
    kind: NDKKind | number;
    id: string;
    sig?: string;
    pubkey: string;
    signatureVerified?: boolean;
    private _author;
    /**
     * The relay that this event was first received from.
     */
    relay: NDKRelay | undefined;
    /**
     * The relays that this event was received from and/or successfully published to.
     */
    get onRelays(): NDKRelay[];
    /**
     * The status of the publish operation.
     */
    publishStatus?: "pending" | "success" | "error";
    publishError?: Error;
    constructor(ndk?: NDK, event?: Partial<NDKRawEvent> | NDKEvent);
    /**
     * Deserialize an NDKEvent from a serialized payload.
     * @param ndk
     * @param event
     * @returns
     */
    static deserialize(ndk: NDK | undefined, event: NDKEventSerialized): NDKEvent;
    /**
     * Returns the event as is.
     */
    rawEvent(): NDKRawEvent;
    set author(user: NDKUser);
    /**
     * Returns an NDKUser for the author of the event.
     */
    get author(): NDKUser;
    /**
     * NIP-73 tagging of external entities
     * @param entity to be tagged
     * @param type of the entity
     * @param markerUrl to be used as the marker URL
     *
     * @example
     * ```typescript
     * event.tagExternal("https://example.com/article/123#nostr", "url");
     * event.tags => [["i", "https://example.com/123"], ["k", "https://example.com"]]
     * ```
     *
     * @example tag a podcast:item:guid
     * ```typescript
     * event.tagExternal("e32b4890-b9ea-4aef-a0bf-54b787833dc5", "podcast:item:guid");
     * event.tags => [["i", "podcast:item:guid:e32b4890-b9ea-4aef-a0bf-54b787833dc5"], ["k", "podcast:item:guid"]]
     * ```
     *
     * @see https://github.com/nostr-protocol/nips/blob/master/73.md
     */
    tagExternal(entity: string, type: NIP73EntityType, markerUrl?: string): void;
    /**
     * Tag a user with an optional marker.
     * @param target What is to be tagged. Can be an NDKUser, NDKEvent, or an NDKTag.
     * @param marker The marker to use in the tag.
     * @param skipAuthorTag Whether to explicitly skip adding the author tag of the event.
     * @param forceTag Force a specific tag to be used instead of the default "e" or "a" tag.
     * @param opts Optional content tagging options to control p tag behavior.
     * @example
     * ```typescript
     * reply.tag(opEvent, "reply");
     * // reply.tags => [["e", <id>, <relay>, "reply"]]
     * ```
     */
    tag(target: NDKTag | NDKUser | NDKEvent, marker?: string, skipAuthorTag?: boolean, forceTag?: string, opts?: ContentTaggingOptions): void;
    /**
     * Return a NostrEvent object, trying to fill in missing fields
     * when possible, adding tags when necessary.
     * @param pubkey {string} The pubkey of the user who the event belongs to.
     * @param opts {ContentTaggingOptions} Options for content tagging.
     * @returns {Promise<NostrEvent>} A promise that resolves to a NostrEvent.
     */
    toNostrEvent(pubkey?: string, opts?: ContentTaggingOptions): Promise<NostrEvent>;
    serialize: (includeSig?: boolean | undefined, includeId?: boolean | undefined) => string;
    getEventHash: () => string;
    validate: () => boolean;
    verifySignature: (persist: boolean) => boolean | undefined;
    /**
     * Is this event replaceable (whether parameterized or not)?
     *
     * This will return true for kind 0, 3, 10k-20k and 30k-40k
     */
    isReplaceable: () => boolean;
    isEphemeral: () => boolean;
    isDvm: () => boolean | 0;
    /**
     * Is this event parameterized replaceable?
     *
     * This will return true for kind 30k-40k
     */
    isParamReplaceable: () => boolean;
    /**
     * Encodes a bech32 id.
     *
     * @param relays {string[]} The relays to encode in the id
     * @returns {string} - Encoded naddr, note or nevent.
     */
    encode: (maxRelayCount?: number | undefined) => string;
    encrypt: (recipient?: NDKUser | undefined, signer?: NDKSigner | undefined, scheme?: NDKEncryptionScheme | undefined) => Promise<void>;
    decrypt: (sender?: NDKUser | undefined, signer?: NDKSigner | undefined, scheme?: NDKEncryptionScheme | undefined) => Promise<void>;
    /**
     * Get all tags with the given name
     * @param tagName {string} The name of the tag to search for
     * @returns {NDKTag[]} An array of the matching tags
     */
    getMatchingTags(tagName: string, marker?: string): NDKTag[];
    /**
     * Check if the event has a tag with the given name
     * @param tagName
     * @param marker
     * @returns
     */
    hasTag(tagName: string, marker?: string): boolean;
    /**
     * Get the first tag with the given name
     * @param tagName Tag name to search for
     * @returns The value of the first tag with the given name, or undefined if no such tag exists
     */
    tagValue(tagName: string, marker?: string): string | undefined;
    /**
     * Gets the NIP-31 "alt" tag of the event.
     */
    get alt(): string | undefined;
    /**
     * Sets the NIP-31 "alt" tag of the event. Use this to set an alt tag so
     * clients that don't handle a particular event kind can display something
     * useful for users.
     */
    set alt(alt: string | undefined);
    /**
     * Gets the NIP-33 "d" tag of the event.
     */
    get dTag(): string | undefined;
    /**
     * Sets the NIP-33 "d" tag of the event.
     */
    set dTag(value: string | undefined);
    /**
     * Remove all tags with the given name (e.g. "d", "a", "p")
     * @param tagName Tag name(s) to search for and remove
     * @param marker Optional marker to check for too
     *
     * @example
     * Remove a tags with a "defer" marker
     * ```typescript
     * event.tags = [
     *   ["a", "....", "defer"],
     *   ["a", "....", "no-defer"],
     * ]
     *
     * event.removeTag("a", "defer");
     *
     * // event.tags => [["a", "....", "no-defer"]]
     *
     * @returns {void}
     */
    removeTag(tagName: string | string[], marker?: string): void;
    /**
     * Replace a tag with a new value. If not found, it will be added.
     * @param tag The tag to replace.
     * @param value The new value for the tag.
     */
    replaceTag(tag: NDKTag): void;
    /**
     * Sign the event if a signer is present.
     *
     * It will generate tags.
     * Repleacable events will have their created_at field set to the current time.
     * @param signer {NDKSigner} The NDKSigner to use to sign the event
     * @param opts {ContentTaggingOptions} Options for content tagging.
     * @returns {Promise<string>} A Promise that resolves to the signature of the signed event.
     */
    sign(signer?: NDKSigner, opts?: ContentTaggingOptions): Promise<string>;
    /**
     *
     * @param relaySet
     * @param timeoutMs
     * @param requiredRelayCount
     * @returns
     */
    publishReplaceable(relaySet?: NDKRelaySet, timeoutMs?: number, requiredRelayCount?: number): Promise<Set<NDKRelay>>;
    /**
     * Attempt to sign and then publish an NDKEvent to a given relaySet.
     * If no relaySet is provided, the relaySet will be calculated by NDK.
     * @param relaySet {NDKRelaySet} The relaySet to publish the even to.
     * @param timeoutM {number} The timeout for the publish operation in milliseconds.
     * @param requiredRelayCount The number of relays that must receive the event for the publish to be considered successful.
     * @param opts {ContentTaggingOptions} Options for content tagging.
     * @returns A promise that resolves to the relays the event was published to.
     */
    publish(relaySet?: NDKRelaySet, timeoutMs?: number, requiredRelayCount?: number, opts?: ContentTaggingOptions): Promise<Set<NDKRelay>>;
    /**
     * Generates tags for users, notes, and other events tagged in content.
     * Will also generate random "d" tag for parameterized replaceable events where needed.
     * @param opts {ContentTaggingOptions} Options for content tagging.
     * @returns {ContentTag} The tags and content of the event.
     */
    generateTags(opts?: ContentTaggingOptions): Promise<ContentTag>;
    get shouldAddClientTag(): boolean;
    get shouldStripClientTag(): boolean;
    muted(): string | null;
    /**
     * Returns the "d" tag of a parameterized replaceable event or throws an error if the event isn't
     * a parameterized replaceable event.
     * @returns {string} the "d" tag of the event.
     *
     * @deprecated Use `dTag` instead.
     */
    replaceableDTag(): string;
    /**
     * Provides a deduplication key for the event.
     *
     * For kinds 0, 3, 10k-20k this will be the event <kind>:<pubkey>
     * For kinds 30k-40k this will be the event <kind>:<pubkey>:<d-tag>
     * For all other kinds this will be the event id
     */
    deduplicationKey(): string;
    /**
     * Returns the id of the event or, if it's a parameterized event, the generated id of the event using "d" tag, pubkey, and kind.
     * @returns {string} The id
     */
    tagId(): string;
    /**
     * Returns a stable reference value for a replaceable event.
     *
     * Param replaceable events are returned in the expected format of `<kind>:<pubkey>:<d-tag>`.
     * Kind-replaceable events are returned in the format of `<kind>:<pubkey>:`.
     *
     * @returns {string} A stable reference value for replaceable events
     */
    tagAddress(): string;
    /**
     * Determines the type of tag that can be used to reference this event from another event.
     * @returns {string} The tag type
     * @example
     * event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
     * event.tagType(); // "a"
     */
    tagType(): "e" | "a";
    /**
     * Get the tag that can be used to reference this event from another event.
     *
     * Consider using referenceTags() instead (unless you have a good reason to use this)
     *
     * @example
     *     event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
     *     event.tagReference(); // ["a", "30000:pubkey:d-code"]
     *
     *     event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
     *     event.tagReference(); // ["e", "eventid"]
     * @returns {NDKTag} The NDKTag object referencing this event
     */
    tagReference(marker?: string): NDKTag;
    /**
     * Get the tags that can be used to reference this event from another event
     * @param marker The marker to use in the tag
     * @param skipAuthorTag Whether to explicitly skip adding the author tag of the event
     * @param forceTag Force a specific tag to be used instead of the default "e" or "a" tag
     * @example
     *     event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
     *     event.referenceTags(); // [["a", "30000:pubkey:d-code"], ["e", "parent-id"]]
     *
     *     event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
     *     event.referenceTags(); // [["e", "parent-id"]]
     * @returns {NDKTag} The NDKTag object referencing this event
     */
    referenceTags(marker?: string, skipAuthorTag?: boolean, forceTag?: string, opts?: ContentTaggingOptions): NDKTag[];
    /**
     * Provides the filter that will return matching events for this event.
     *
     * @example
     *    event = new NDKEvent(ndk, { kind: 30000, pubkey: 'pubkey', tags: [ ["d", "d-code"] ] });
     *    event.filter(); // { "#a": ["30000:pubkey:d-code"] }
     * @example
     *    event = new NDKEvent(ndk, { kind: 1, pubkey: 'pubkey', id: "eventid" });
     *    event.filter(); // { "#e": ["eventid"] }
     *
     * @returns The filter that will return matching events for this event
     */
    filter(): NDKFilter;
    nip22Filter(): NDKFilter;
    /**
     * Generates a deletion event of the current event
     *
     * @param reason The reason for the deletion
     * @param publish Whether to publish the deletion event automatically
     * @returns The deletion event
     */
    delete(reason?: string, publish?: boolean): Promise<NDKEvent>;
    /**
     * Establishes whether this is a NIP-70-protectede event.
     * @@satisfies NIP-70
     */
    set isProtected(val: boolean);
    /**
     * Whether this is a NIP-70-protected event.
     * @@satisfies NIP-70
     */
    get isProtected(): boolean;
    /**
     * Fetch an event tagged with the given tag following relay hints if provided.
     * @param tag The tag to search for
     * @param marker The marker to use in the tag (e.g. "root")
     * @returns The fetched event or null if no event was found, undefined if no matching tag was found in the event
     * * @example
     * const replyEvent = await ndk.fetchEvent("nevent1qqs8x8vnycyha73grv380gmvlury4wtmx0nr9a5ds2dngqwgu87wn6gpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3ql2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqz4cwjd")
     * const originalEvent = await replyEvent.fetchTaggedEvent("e", "reply");
     * console.log(replyEvent.encode() + " is a reply to event " + originalEvent?.encode());
     */
    fetchTaggedEvent: (tag: string, marker?: string | undefined) => Promise<NDKEvent | null | undefined>;
    /**
     * Fetch the root event of the current event.
     * @returns The fetched root event or null if no event was found
     * @example
     * const replyEvent = await ndk.fetchEvent("nevent1qqs8x8vnycyha73grv380gmvlury4wtmx0nr9a5ds2dngqwgu87wn6gpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3ql2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqz4cwjd")
     * const rootEvent = await replyEvent.fetchRootEvent();
     * console.log(replyEvent.encode() + " is a reply in the thread " + rootEvent?.encode());
     */
    fetchRootEvent: (subOpts?: NDKSubscriptionOptions | undefined) => Promise<NDKEvent | null | undefined>;
    /**
     * Fetch the event the current event is replying to.
     * @returns The fetched reply event or null if no event was found
     */
    fetchReplyEvent: (subOpts?: NDKSubscriptionOptions | undefined) => Promise<NDKEvent | null | undefined>;
    /**
     * NIP-18 reposting event.
     *
     * @param publish Whether to publish the reposted event automatically @default true
     * @param signer The signer to use for signing the reposted event
     * @returns The reposted event
     *
     * @function
     */
    repost: (publish?: boolean | undefined, signer?: NDKSigner | undefined) => Promise<NDKEvent>;
    /**
     * React to an existing event
     *
     * @param content The content of the reaction
     */
    react(content: string, publish?: boolean): Promise<NDKEvent>;
    /**
     * Checks whether the event is valid per underlying NIPs.
     *
     * This method is meant to be overridden by subclasses that implement specific NIPs
     * to allow the enforcement of NIP-specific validation rules.
     *
     * Otherwise, it will only check for basic event properties.
     *
     */
    get isValid(): boolean;
    get inspect(): string;
    /**
     * Dump the event to console for debugging purposes.
     * Prints a JSON stringified version of rawEvent() with indentation
     * and also lists all relay URLs for onRelays.
     */
    dump(): void;
    /**
     * Creates a reply event for the current event.
     *
     * This function will use NIP-22 when appropriate (i.e. replies to non-kind:1 events).
     * This function does not have side-effects; it will just return an event with the appropriate tags
     * to generate the reply event; the caller is responsible for publishing the event.
     *
     * @param forceNip22 - Optional flag to force NIP-22 style replies (kind 1111) regardless of the original event's kind
     * @param opts - Optional content tagging options
     */
    reply(forceNip22?: boolean, opts?: ContentTaggingOptions): NDKEvent;
}
/**
 * Discriminated union types for signed and unsigned events
 */
/**
 * An NDKEvent that has been signed and has all required fields for relay transmission
 */
type NDKSignedEvent = NDKEvent & {
    readonly signed: true;
    id: string;
    sig: string;
    created_at: number;
};

type NDKEncryptionScheme = "nip04" | "nip44";

declare enum NdkNutzapStatus {
    INITIAL = "initial",
    PROCESSING = "processing",
    REDEEMED = "redeemed",
    SPENT = "spent",
    MISSING_PRIVKEY = "missing_privkey",
    TEMPORARY_ERROR = "temporary_error",
    PERMANENT_ERROR = "permanent_error",
    INVALID_NUTZAP = "invalid_nutzap"
}
interface NDKNutzapState {
    nutzap?: NDKNutzap;
    status: NdkNutzapStatus;
    redeemedById?: NDKEventId;
    errorMessage?: string;
    redeemedAmount?: number;
}

/**
 * A signer that uses an in-memory private key (nsec).
 *
 * @example
 * ```ts
 * const signer = NDKPrivateKeySigner.generate();
 * console.log('your nsec is', signer.nsec);
 * console.log('your pubkey is', signer.pubkey);
 * console.log('your npub is', signer.npub);
 * ```
 *
 * @example
 * ```ts
 * const signer = new NDKPrivateKeySigner(nsec);
 * ```
 */
declare class NDKPrivateKeySigner implements NDKSigner {
    private _user;
    private _privateKey;
    private _pubkey?;
    /**
     * Create a new signer from a private key.
     * @param privateKey - The private key to use in hex form or nsec.
     * @param ndk - The NDK instance to use.
     *
     * @ai-guardrail
     * If you have an nsec (bech32-encoded private key starting with "nsec1"), you can pass it directly
     * to this constructor without decoding it first. The constructor handles both hex and nsec formats automatically.
     * DO NOT use nip19.decode() to convert nsec to hex before passing it here - just pass the nsec string directly.
     */
    constructor(privateKeyOrNsec: Uint8Array | string, ndk?: NDK);
    /**
     * Get the private key in hex form.
     */
    get privateKey(): string;
    /**
     * Get the public key in hex form.
     */
    get pubkey(): string;
    /**
     * Get the private key in nsec form.
     */
    get nsec(): string;
    /**
     * Get the public key in npub form.
     */
    get npub(): string;
    /**
     * Encrypt the private key with a password to ncryptsec format.
     * @param password - The password to encrypt the private key.
     * @param logn - The log2 of the scrypt N parameter (default: 16).
     * @param ksb - The key security byte (0x00, 0x01, or 0x02, default: 0x02).
     * @returns The encrypted private key in ncryptsec format.
     *
     * @example
     * ```ts
     * const signer = new NDKPrivateKeySigner(nsec);
     * const ncryptsec = signer.encryptToNcryptsec("my-password");
     * console.log('encrypted key:', ncryptsec);
     * ```
     */
    encryptToNcryptsec(password: string, logn?: number, ksb?: 0x00 | 0x01 | 0x02): string;
    /**
     * Generate a new private key.
     */
    static generate(): NDKPrivateKeySigner;
    /**
     * Create a signer from an encrypted private key (ncryptsec) using a password.
     * @param ncryptsec - The encrypted private key in ncryptsec format.
     * @param password - The password to decrypt the private key.
     * @param ndk - Optional NDK instance.
     * @returns A new NDKPrivateKeySigner instance.
     *
     * @example
     * ```ts
     * const signer = NDKPrivateKeySigner.fromNcryptsec(
     *   "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p",
     *   "my-password"
     * );
     * console.log('your pubkey is', signer.pubkey);
     * ```
     */
    static fromNcryptsec(ncryptsec: string, password: string, ndk?: NDK): NDKPrivateKeySigner;
    /**
     * Noop in NDKPrivateKeySigner.
     */
    blockUntilReady(): Promise<NDKUser>;
    /**
     * Get the user.
     */
    user(): Promise<NDKUser>;
    /**
     * Get the user.
     */
    get userSync(): NDKUser;
    sign(event: NostrEvent): Promise<string>;
    encryptionEnabled(scheme?: NDKEncryptionScheme): Promise<NDKEncryptionScheme[]>;
    encrypt(recipient: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
    decrypt(sender: NDKUser, value: string, scheme?: NDKEncryptionScheme): Promise<string>;
    /**
     * Serializes the signer's private key into a storable format.
     * @returns A JSON string containing the type and the hex private key.
     */
    toPayload(): string;
    /**
     * Deserializes the signer from a payload string.
     * @param payloadString The JSON string obtained from toPayload().
     * @param ndk Optional NDK instance.
     * @returns An instance of NDKPrivateKeySigner.
     */
    static fromPayload(payloadString: string, ndk?: NDK): Promise<NDKPrivateKeySigner>;
}

type Nip07RelayMap = {
    [key: string]: {
        read: boolean;
        write: boolean;
    };
};
type Nip44 = {
    encrypt: (recipient: Hexpubkey, value: string) => Promise<string>;
    decrypt: (sender: Hexpubkey, value: string) => Promise<string>;
};
declare global {
    interface Window {
        nostr?: {
            getPublicKey(): Promise<string>;
            signEvent(event: NostrEvent): Promise<{
                sig: string;
            }>;
            getRelays?: () => Promise<Nip07RelayMap>;
            nip04?: {
                encrypt(recipientHexPubKey: string, value: string): Promise<string>;
                decrypt(senderHexPubKey: string, value: string): Promise<string>;
            };
            nip44?: Nip44;
        };
    }
}

type Names = "alice" | "bob" | "carol" | "dave" | "eve";
/**
 * Generates deterministic test users for consistent, reproducible testing.
 *
 * Provides predefined users (alice, bob, carol, dave, eve) with static keypairs,
 * ensuring your tests produce the same results every time. Perfect for testing
 * multi-user interactions in your Nostr application.
 *
 * @example
 * ```typescript
 * // Get a deterministic test user
 * const alice = await UserGenerator.getUser('alice', ndk);
 * const bob = await UserGenerator.getUser('bob', ndk);
 *
 * // Use in your app tests
 * const dm = await myApp.sendMessage(alice, bob, 'Hello!');
 * ```
 */
declare class UserGenerator {
    static privateKeys: Record<string, string>;
    /**
     * Get a deterministic test user by name.
     *
     * Returns a test user with a predefined keypair, ensuring consistent behavior
     * across test runs. Use this when testing features that involve specific users.
     *
     * @param name The name of the user (alice, bob, carol, dave, eve)
     * @param ndk Optional NDK instance to attach to the user
     * @returns The NDK user with a deterministic keypair
     *
     * @example
     * ```typescript
     * const alice = await UserGenerator.getUser('alice', ndk);
     * expect(alice.pubkey).toBe('e9e4276490374a0daf7759fd5f475deff6ffb9b0fc5fa98c902b5f4b2fe3bba1');
     * ```
     */
    static getUser(name: Names, ndk?: NDK): Promise<NDKUser>;
    /**
     * Get the private key for a specific test user
     * @param name The name of the user (alice, bob, carol, dave, eve)
     * @returns The private key hex string
     */
    static getPrivateKey(name: Names): string;
    /**
     * Get a user with a random private key
     * @param ndk The NDK instance to use for the user
     * @returns The NDK user
     */
    static getRandomUser(ndk?: NDK): Promise<NDKUser>;
}
/**
 * Generates signers for test users to sign events in your application tests.
 *
 * Provides signers for predefined test users, allowing you to test event signing,
 * publishing, and authentication flows in your Nostr application.
 *
 * @example
 * ```typescript
 * // Get a signer for a test user
 * const aliceSigner = SignerGenerator.getSigner('alice');
 * ndk.signer = aliceSigner;
 *
 * // Now alice can sign events in your app
 * await myApp.publishNote('Hello, Nostr!');
 * ```
 */
declare class SignerGenerator {
    /**
     * Get a signer for a specific test user
     * @param name The name of the user (alice, bob, carol, dave, eve)
     * @returns The NDK signer
     */
    static getSigner(name: Names): NDKPrivateKeySigner;
    static sign(event: NDKEvent, user: Names): Promise<NDKEvent>;
    /**
     * Generate a random signer
     * @returns The NDK signer
     */
    static getRandomSigner(): NDKPrivateKeySigner;
}
/**
 * High-level event factory for creating test events with proper relationships and tagging.
 *
 * Provides convenient methods for creating common event patterns like notes, DMs,
 * replies, and conversation threads. Automatically handles proper NIP-10 tagging
 * and event relationships for testing your app's event handling logic.
 *
 * @example
 * ```typescript
 * const factory = new TestEventFactory(ndk);
 * const alice = await UserGenerator.getUser('alice', ndk);
 * const bob = await UserGenerator.getUser('bob', ndk);
 *
 * // Create a note
 * const note = await factory.createSignedTextNote('Hello!', alice);
 *
 * // Create a reply
 * const reply = await factory.createReply(note, 'Hi back!', bob);
 *
 * // Create a DM
 * const dm = await factory.createDirectMessage('Secret message', alice, bob);
 *
 * // Create a conversation thread
 * const thread = await factory.createEventChain('Original post', alice, [
 *   { author: bob, content: 'First reply' },
 *   { author: alice, content: 'Response' }
 * ]);
 * ```
 */
declare class TestEventFactory {
    private ndk;
    constructor(ndk: NDK);
    /**
     * Create a signed text note from a specific user
     * @param content The content of the note
     * @param user The user that authored the note, or name of predefined test user
     * @param kind The kind of the event (defaults to 1)
     * @returns The signed event
     */
    createSignedTextNote(content: string, user: NDKUser | Names | undefined, kind?: number): Promise<any>;
    /**
     * Create a direct message from one user to another
     * @param content The content of the message
     * @param fromUser The sender (author)
     * @param toUser The recipient
     * @returns The created event (not necessarily signed)
     */
    createDirectMessage(content: string, fromUser: NDKUser | Names, toUser: NDKUser | Names): Promise<any>;
    /**
     * Create a reply to an event
     * @param originalEvent The event being replied to
     * @param content The content of the reply
     * @param fromUser The author of the reply
     * @param kind The kind of the reply (defaults to same as original for kind 1, or 1111 for other kinds)
     * @returns The created reply event (not necessarily signed)
     */
    createReply(originalEvent: any, content: string, fromUser: NDKUser | Names, kind?: number): Promise<any>;
    /**
     * Creates a chain of events (e.g., a thread)
     * @param initialContent Content of the first message
     * @param replies Array of {content, author} objects for each reply
     * @returns Array of events in the chain
     */
    createEventChain(initialContent: string, initialAuthor: NDKUser | Names, replies: Array<{
        content: string;
        author: NDKUser | Names;
    }>): Promise<any[]>;
}
/**
 * Complete test environment with NDK, users, and event factory pre-configured.
 *
 * Provides a ready-to-use test environment that combines NDK instance, event factory,
 * and convenient access to test users and signers. Reduces boilerplate in your tests.
 *
 * @example
 * ```typescript
 * const fixture = new TestFixture();
 *
 * // Access NDK instance
 * fixture.ndk.connect();
 *
 * // Get test users
 * const alice = await fixture.getUser('alice');
 *
 * // Setup signer
 * fixture.setupSigner('alice');
 *
 * // Use event factory
 * const note = await fixture.eventFactory.createSignedTextNote('Test', alice);
 *
 * // Test your app with this environment
 * ```
 */
declare class TestFixture {
    ndk: NDK;
    eventFactory: TestEventFactory;
    constructor();
    /**
     * Get a predefined test user
     * @param name The name of the user (alice, bob, carol, dave, eve)
     * @returns The NDK user
     */
    getUser(name: Names): Promise<NDKUser>;
    /**
     * Get a signer for a predefined test user
     * @param name The name of the user
     * @returns The NDK signer
     */
    getSigner(name: Names): NDKPrivateKeySigner;
    /**
     * Set up the NDK instance with a specific signer
     * @param name The name of the predefined user to use as signer
     */
    setupSigner(name: Names): void;
}

/**
 * Controls time in tests for testing time-dependent application logic.
 *
 * Provides utilities to advance fake timers, control async operations, and test
 * features like retries, delays, and scheduled tasks in your Nostr application.
 * Works with Vitest's fake timer system.
 *
 * @example
 * ```typescript
 * import { vi } from 'vitest';
 * import { TimeController } from '@nostr-dev-kit/ndk/test';
 *
 * beforeEach(() => {
 *   vi.useFakeTimers();
 *   TimeController.setViObject(vi);
 * });
 *
 * it('should retry after delay', async () => {
 *   const promise = myApp.retryPublish(event); // retries after 5 seconds
 *
 *   // Advance time by 5 seconds
 *   await TimeController.tickAsync(5000);
 *
 *   await expect(promise).resolves.toBeTruthy();
 * });
 *
 * afterEach(() => {
 *   TimeController.reset();
 *   vi.useRealTimers();
 * });
 * ```
 */
declare class TimeController {
    private static viObject;
    /**
     * Set the Vitest object to use for time control
     */
    static setViObject(vi: any): void;
    /**
     * Advance timers by a specified number of milliseconds
     */
    static advanceTime(ms: number): void;
    /**
     * Advance timers asynchronously by a specified number of milliseconds
     */
    static tickAsync(ms?: number): Promise<void>;
    /**
     * Clear all timers
     */
    static reset(): void;
    /**
     * Wait for the next tick of the event loop
     */
    static waitForNextTick(): Promise<void>;
}
/**
 * Helper function to create a TimeController with automatic setup/teardown.
 *
 * Convenience wrapper that automatically sets up fake timers before your test
 * and restores real timers after, reducing boilerplate in your test files.
 *
 * @param viObject The Vitest `vi` object
 * @returns A TimeController instance configured for your test
 *
 * @example
 * ```typescript
 * import { vi } from 'vitest';
 * import { withTimeControl } from '@nostr-dev-kit/ndk/test';
 *
 * const timeController = withTimeControl(vi);
 *
 * it('should handle delays', async () => {
 *   const promise = myApp.delayedOperation();
 *   await timeController.tickAsync(1000);
 *   await expect(promise).resolves.toBeTruthy();
 * });
 * ```
 */
declare function withTimeControl(viObject: any): (fn: (timeController: typeof TimeController) => Promise<void>) => (() => Promise<void>);

/** biome-ignore-all lint/complexity/noStaticOnlyClass: <test purposes> */
/** biome-ignore-all lint/suspicious/noExplicitAny: <test purposes> */

/**
 * Low-level event generator for creating test events in your Nostr application tests.
 *
 * Provides simple methods to create various types of Nostr events with automatic signing.
 * Must call `setNDK()` once before using any event creation methods.
 *
 * @example
 * ```typescript
 * import { EventGenerator, UserGenerator } from '@nostr-dev-kit/ndk/test';
 *
 * // Initialize once in your test setup
 * EventGenerator.setNDK(ndk);
 *
 * // Create events
 * const alice = await UserGenerator.getUser('alice', ndk);
 * const note = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
 * const dm = await EventGenerator.createEncryptedDirectMessage('Secret', alice.pubkey, bob.pubkey);
 *
 * // Use these events to test your app's event handling
 * ```
 */
declare class EventGenerator {
    private static ndk;
    static setNDK(ndk: NDK): void;
    static createEvent(kind?: number, content?: string, pubkey?: string): NDKEvent;
    static createSignedTextNote(content: string, pubkey?: string): Promise<NDKEvent>;
    static createEncryptedDirectMessage(content: string, from: string, to: string): Promise<NDKEvent>;
    static createRepost(originalEvent: NDKEvent, pubkey?: string): Promise<NDKEvent>;
    static createParameterizedReplaceable(kind: number, content: string, pubkey?: string, dTag?: string): Promise<NDKEvent>;
    private static requireNDK;
    private static resolvePubkey;
}

type Proof = {
    id: string;
    amount: number;
    secret: string;
    C: string;
};
/**
 * Creates a mock Cashu nutzap for testing zap/payment features in your application.
 *
 * Generates a complete NIP-61 nutzap event with Cashu tokens, perfect for testing
 * payment flows, zap handling, and wallet integration in your Nostr app without
 * requiring real mints or tokens.
 *
 * @param mint The mint URL
 * @param amount The amount in satoshis
 * @param ndk The NDK instance
 * @param opts Configuration options
 * @param opts.senderPk The private key signer of the sender (defaults to random)
 * @param opts.recipientPubkey The nostr pubkey of the recipient
 * @param opts.content Optional comment/message with the nutzap
 * @param opts.eventId Optional event ID being zapped (for replay protection)
 * @returns A signed nutzap event ready for testing
 *
 * @example
 * ```typescript
 * import { mockNutzap, UserGenerator } from '@nostr-dev-kit/ndk/test';
 *
 * const alice = await UserGenerator.getUser('alice', ndk);
 * const bob = await UserGenerator.getUser('bob', ndk);
 *
 * // Create a nutzap from alice to bob
 * const nutzap = await mockNutzap(
 *   'https://mint.example.com',
 *   1000, // 1000 sats
 *   ndk,
 *   {
 *     recipientPubkey: bob.pubkey,
 *     content: 'Great post!',
 *     eventId: originalEvent.id
 *   }
 * );
 *
 * // Test your app's nutzap handling
 * await myApp.handleNutzap(nutzap);
 * ```
 */
declare function mockNutzap(mint: string, amount: number, ndk: any, { senderPk, recipientPubkey, content, eventId, }?: {
    senderPk?: any;
    recipientPubkey?: string;
    content?: string;
    eventId?: string;
}): Promise<NDKNutzap>;
/**
 * Creates a mock Cashu proof for testing token handling in your application.
 *
 * Generates individual Cashu proofs with optional P2PK locking, useful for testing
 * token validation, redemption, and wallet operations without real Cashu tokens.
 *
 * @param C The commitment point (usually mint URL for testing)
 * @param amount The amount in satoshis
 * @param p2pk Optional pubkey for P2PK locking the proof
 * @param proofTags Optional tags for proof secret (e.g., [["e", "event-id"], ["P", "sender-pubkey"]])
 * @returns A mock Cashu proof object
 *
 * @example
 * ```typescript
 * import { mockProof } from '@nostr-dev-kit/ndk/test';
 *
 * // Create a simple proof
 * const proof = mockProof('https://mint.example.com', 100);
 *
 * // Create a P2PK-locked proof
 * const lockedProof = mockProof(
 *   'https://mint.example.com',
 *   500,
 *   bobPubkey, // locked to bob
 *   [['P', alicePubkey]] // from alice
 * );
 *
 * // Test your app's proof validation
 * const isValid = await myApp.validateProof(lockedProof);
 * ```
 */
declare function mockProof(C: string, amount: number, p2pk?: string, proofTags?: [string, string][]): Proof;

interface RelayMockOptions {
    simulateDisconnect?: boolean;
    disconnectAfter?: number;
    connectionDelay?: number;
    autoConnect?: boolean;
    failNextPublish?: boolean;
}
/**
 * Mock Nostr relay for testing your application without real relay connections.
 *
 * Simulates a full Nostr relay with configurable behavior including connection delays,
 * disconnections, and publish failures. Perfect for testing your app's relay interaction
 * logic without network dependencies.
 *
 * @example
 * ```typescript
 * import { RelayMock } from '@nostr-dev-kit/ndk/test';
 *
 * // Create a mock relay
 * const relay = new RelayMock('wss://relay.example.com', {
 *   connectionDelay: 100,      // Simulate 100ms connection delay
 *   simulateDisconnect: true,  // Randomly disconnect
 *   disconnectAfter: 5000      // Disconnect after 5 seconds
 * });
 *
 * // Use it in your NDK instance
 * ndk.pool.relays.set(relay.url, relay);
 *
 * // Simulate events from relay
 * const event = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
 * relay.simulateEvent(event);
 * relay.simulateEOSE();
 *
 * // Test publish failures
 * relay.failNextPublish = true;
 * await myApp.publishNote('This will fail');
 * ```
 */
declare class RelayMock extends EventEmitter$1 {
    url: string;
    private _status;
    messageLog: Array<{
        direction: "in" | "out";
        message: string;
    }>;
    private activeSubscriptions;
    validatedEvents: number;
    nonValidatedEvents: number;
    options: Required<RelayMockOptions>;
    constructor(url?: string, options?: RelayMockOptions);
    connect(): Promise<void>;
    disconnect(): Promise<void>;
    get status(): NDKRelayStatus;
    send(message: string): void;
    publish(event: NDKEvent): Promise<boolean>;
    subscribe(subscription: NDKSubscription, filters: NDKFilter[]): void;
    shouldValidateEvent(): boolean;
    /**
     * Track the number of validated events (used in tests)
     */
    addValidatedEvent(): void;
    /**
     * Track the number of non-validated events (used in tests)
     */
    addNonValidatedEvent(): void;
    /**
     * Simulate receiving a raw message
     */
    simulateReceiveMessage(message: string): void;
    /**
     * Simulate receiving an event
     */
    simulateEvent(event: NDKEvent, subId?: string): Promise<void>;
    /**
     * Simulate end of stored events
     */
    simulateEOSE(subId: string): void;
    /**
     * Simulate a NOTICE message from the relay
     */
    simulateNotice(message: string): void;
    reset(): void;
}

/**
 * Mock relay pool for testing applications with multiple Nostr relays.
 *
 * Manages multiple mock relays and provides convenient methods to simulate
 * events across all or specific relays. Perfect for testing your app's
 * multi-relay behavior, redundancy, and relay selection logic.
 *
 * @example
 * ```typescript
 * import { RelayPoolMock, EventGenerator, UserGenerator } from '@nostr-dev-kit/ndk/test';
 *
 * const pool = new RelayPoolMock();
 * const ndk = new NDK({ explicitRelayUrls: [] });
 * ndk.pool = pool;
 *
 * // Add mock relays
 * pool.addMockRelay('wss://relay1.example.com');
 * pool.addMockRelay('wss://relay2.example.com', {
 *   connectionDelay: 200
 * });
 *
 * // Simulate event on all relays
 * const alice = await UserGenerator.getUser('alice', ndk);
 * const event = await EventGenerator.createSignedTextNote('Hello!', alice.pubkey);
 * pool.simulateEventOnAll(event);
 *
 * // Simulate event on specific relays
 * pool.simulateEventOn(['wss://relay1.example.com'], event);
 *
 * // Send EOSE to all relays
 * pool.simulateEOSEOnAll(subscriptionId);
 *
 * // Cleanup
 * pool.disconnectAll();
 * pool.resetAll();
 * ```
 */
declare class RelayPoolMock {
    mockRelays: Map<string, RelayMock>;
    relays: Set<RelayMock>;
    private eventListeners;
    private onceListeners;
    addMockRelay(url: string, options?: {}): RelayMock;
    getMockRelay(url: string): RelayMock | undefined;
    addRelay(relay: RelayMock): void;
    removeRelay(relay: RelayMock): void;
    simulateEventOnAll(event: NDKEvent): void;
    simulateEventOn(relayUrls: string[], event: NDKEvent): void;
    simulateEOSEOnAll(subscriptionId: string): void;
    disconnectAll(): void;
    resetAll(): void;
    permanentAndConnectedRelays(): RelayMock[];
    connectedRelays(): RelayMock[];
    getRelay(url: string, connect?: boolean, createIfNotExists?: boolean, _filters?: NDKFilter[]): RelayMock;
    on(eventName: string, callback: Function): void;
    once(eventName: string, callback: Function): void;
    off(eventName: string, callback: Function): void;
    emit(eventName: string, ...args: any[]): void;
    useTemporaryRelay(_relay: RelayMock, _filters?: NDKFilter[], _subscription?: any): void;
    blacklistRelayUrls: Set<string>;
}

export { EventGenerator, type Proof, RelayMock, RelayPoolMock, SignerGenerator, TestEventFactory, TestFixture, TimeController, UserGenerator, mockNutzap, mockProof, withTimeControl };
