nostr-fetch
Version:
A utility library that allows JS/TS apps to effortlessly fetch past events from Nostr relays
358 lines • 16.2 kB
TypeScript
import { type NostrFetcherBackendInitializer, type NostrFetcherCommonOptions } from "@nostr-fetch/kernel/fetcherBackend";
import { type EventVerifier, type NostrEvent } from "@nostr-fetch/kernel/nostr";
import { type DefaultFetcherBackendOptions } from "./fetcherBackend";
import { type RelayCapCheckerInitializer } from "./fetcherHelper";
import { type FetchFilter, type FetchFilterKeyElem, type FetchFilterKeyName, type FetchStatsListener, type FetchTimeRangeFilter } from "./types";
/**
* Nostr event with extra fields.
*/
export type NostrEventExt<SeenOn extends boolean = false> = NostrEvent & {
seenOn: SeenOn extends true ? string[] : undefined;
};
/**
* Pair of the "key" of events and list of events which have that key.
*
* It is the type of elements of `AsyncIterable` returned from {@linkcode NostrFetcher.fetchLatestEventsPerKey}.
*/
export type NostrEventListWithKey<K extends FetchFilterKeyName, SeenOn extends boolean> = {
key: FetchFilterKeyElem<K>;
events: NostrEventExt<SeenOn>[];
};
/**
* Pair of the "key" of an event and the event which has that key. If no event found matching the key, it will be `undefined`.
*
* It is the type of elements of `AsyncIterable` returned from {@linkcode NostrFetcher.fetchLastEventPerKey}.
*/
export type NostrEventWithKey<K extends FetchFilterKeyName, SeenOn extends boolean> = {
key: FetchFilterKeyElem<K>;
event: NostrEventExt<SeenOn> | undefined;
};
/**
* Pair of the pubkey of event author and list of events from that author.
*
* It is the type of elements of `AsyncIterable` returned from {@linkcode NostrFetcher.fetchLatestEventsPerAuthor}.
*/
export type NostrEventListWithAuthor<SeenOn extends boolean> = {
author: string;
events: NostrEventExt<SeenOn>[];
};
/**
* Pair of the pubkye of event author and an event from that author. If no event found from the author, it will be `undefined`.
*
* It is the type of elements of `AsyncIterable` returned from {@linkcode NostrFetcher.fetchLastEventPerAuthor}.
*/
export type NostrEventWithAuthor<SeenOn extends boolean> = {
author: string;
event: NostrEventExt<SeenOn> | undefined;
};
/**
* Common options for all the fetch methods.
*/
export type FetchOptions<SeenOn extends boolean = false> = {
/**
* If specified, the fetcher uses the given function as an event signature verifier instead of the default one.
*
* The function must return `true` if the event signature is valid. Otherwise, it should return `false`.
*
* @example
* // How to use nostr-wasm's verifyEvent() with nostr-fetch
* import { NostrFetcher, type NostrEvent } from "nostr-fetch";
* import { initNostrWasm } from "nostr-wasm";
*
* const nw = await initNostrWasm();
* const nwVerifyEvent = (ev: NostrEvent) => {
* try {
* nw.verifyEvent(ev);
* return true;
* } catch {
* return false;
* }
* };
* const fetcher = NostrFetcher.init({
* eventVerifier: nwVerifyEvent,
* });
*/
eventVerifier?: EventVerifier;
/**
* If true, the fetcher skips event signature verification.
*
* Note: This option has no effect under some relay pool adapters.
* Check the document of the relay pool adapter you want to use.
*
* @default false
*
* @deprecated This option will be removed in nostr-fetch v1. Set the `noopVerifier` to the `eventVerifier` option instead of turning this on.
*/
skipVerification?: boolean;
/**
* If true, the fetcher skips a check that events from relays are certainly match with filters in REQuest.
*
* By default, fetchers perform the check to protect clients from malicious relays.
*
* @default false
*/
skipFilterMatching?: boolean;
/**
* If true, `seenOn` property is appended to every returned events.
* The value of `seenOn` is array of relay URLs on which the event have been seen.
*
* @default false
*/
withSeenOn?: SeenOn;
/**
* The function for listening fetch statistics.
*
* @default undefined
*/
statsListener?: FetchStatsListener | undefined;
/**
* How often fetch statistics is notified to the listener (specified via `statsListener`), in milliseconds.
*
* @default 1000
*/
statsNotifIntervalMs?: number;
/**
* The maximum amount of time allowed to attempt to connect to relays, in milliseconds.
*
* @default 5000
*/
connectTimeoutMs?: number;
/**
* The `AbortSignal` used to abort an event fetching.
*
* @default undefined
*/
signal?: AbortSignal | undefined;
/**
* The `AbortSignal` used to abort an event fetching.
*
* @default undefined
*
* @deprecated Set `signal` option instead.
*/
abortSignal?: AbortSignal | undefined;
/**
* The maximum amount of time to wait for events from relay before a subscription is automatically aborted before EOSE, in milliseconds.
*
* @default 10000
*/
abortSubBeforeEoseTimeoutMs?: number;
/**
* `limit` value to be used in internal subscriptions.
* You may want to lower this value if relays you use have limit on value of `limit`.
*
* @default 5000
*/
limitPerReq?: number;
};
/**
* Options for {@linkcode NostrFetcher.allEventsIterator}.
*/
export type AllEventsIterOptions<SeenOn extends boolean = false> = FetchOptions<SeenOn> & {
/**
* If true, the backpressure mode is enabled.
*
* In the backpressure mode, a fetcher is automatically slowed down when the consumer of events is slower than the fetcher (producer of events).
*
* This feature may be useful for jobs like transferring events from relays to other relays.
*
* @default false
*/
enableBackpressure?: boolean;
};
/**
* Options for {@linkcode NostrFetcher.fetchAllEvents}.
*/
export type FetchAllOptions<SeenOn extends boolean = false> = FetchOptions<SeenOn> & {
/**
* If true, resulting events are sorted in "newest to oldest" order.
*
* @default false
*/
sort?: boolean;
};
/**
* Options for "fetch latest N events" kind of fetchers, such as {@linkcode NostrFetcher.fetchLatestEvents}.
*/
export type FetchLatestOptions<SeenOn extends boolean = false> = FetchOptions<SeenOn> & {
/**
* Takes unixtime in second. If specified, fetch latest events **as of the time**.
*
* Note: it is useful only for fetching *regular* events. Using this for replaceable events will result in an unexpected behavior.
*/
asOf?: number | undefined;
/**
* If true, the "reduced verification" mode is enabled.
*
* In the reduced verification mode, event signature verification is performed only to minimum amount of events enough to ensure validity.
*
* @default false
*
* @deprecated This option will be removed in nostr-fetch v1. Fetch with `eventVerifier: noopVerifier` first, then verify fetched events by yourself.
*/
reduceVerification?: boolean;
};
/**
* Type of the first argument of {@linkcode NostrFetcher.fetchLatestEventsPerAuthor}/{@linkcode NostrFetcher.fetchLastEventPerAuthor}.
*/
export type KeysAndRelays<K extends FetchFilterKeyName> = {
keys: FetchFilterKeyElem<K>[];
relayUrls: string[];
} | Iterable<[key: FetchFilterKeyElem<K>, relayUrls: string[]]>;
/**
* Type of the first argument of {@linkcode NostrFetcher.fetchLatestEventsPerAuthor}/{@linkcode NostrFetcher.fetchLastEventPerAuthor}.
*/
export type AuthorsAndRelays = RelaySetForAllAuthors | RelaySetsPerAuthor;
/**
* Use same relay set for all authors
*/
type RelaySetForAllAuthors = {
authors: string[];
relayUrls: string[];
};
/**
* Use saperate relay set for each author. Typically `Map<string, string[]>`
*/
type RelaySetsPerAuthor = Iterable<[author: string, relayUrls: string[]]>;
/**
* The entry point of the Nostr event fetching.
*
* It sits on top of a Nostr relay pool implementation which manages connections to Nostr relays. It is recommended to reuse single `NostrFetcher` instance in entire app.
*
* You must instantiate `NostrFetcher` with static methods like {@linkcode NostrFetcher.init} or {@linkcode NostrFetcher.withCustomPool} instead of the constructor.
*/
export declare class NostrFetcher {
#private;
private constructor();
/**
* Initializes {@linkcode NostrFetcher} with the default relay pool implementation.
*
* If you are on an runtime that doesn't have a native WebSocket implementation (e.g. Node.js < v22),
* you may want to set custom `WebSocket` constructor imported from an external package as follows:
*
* ```ts
* import { NostrFetcher } from "nostr-fetch";
* import WebSocket from "ws";
*
* const fetcher = NostrFetcher.init({
* webSocketConstructor: WebSocket
* });
* ```
*/
static init(options?: NostrFetcherCommonOptions & DefaultFetcherBackendOptions, initRelayCapChecker?: RelayCapCheckerInitializer): NostrFetcher;
/**
* Initializes {@linkcode NostrFetcher} with the given adapted custom relay pool implementation.
*
* @example
* ```ts
* const pool = new SimplePool();
* const fetcher = NostrFetcher.withCustomPool(simplePoolAdapter(pool));
* ```
*/
static withCustomPool(poolAdapter: NostrFetcherBackendInitializer, options?: NostrFetcherCommonOptions, initRelayCapChecker?: RelayCapCheckerInitializer): NostrFetcher;
/**
* Returns an async iterable of all events matching the filter from Nostr relays specified by the array of URLs.
*
* You can iterate over events using `for-await-of` loop.
*
* Note: there are no guarantees about the order of returned events.
*
* Throws {@linkcode NostrFetchError} if `timeRangeFilter` is invalid (`since` > `until`).
*/
allEventsIterator<SeenOn extends boolean = false>(relayUrls: string[], filter: FetchFilter, timeRangeFilter: FetchTimeRangeFilter, options?: AllEventsIterOptions<SeenOn>): AsyncIterable<NostrEventExt<SeenOn>>;
/**
* Fetches all events matching the filter from Nostr relays specified by the array of URLs,
* and collect them into an array.
*
* Note: there are no guarantees about the order of returned events if `sort` options is not specified.
*
* Throws {@linkcode NostrFetchError} if `timeRangeFilter` is invalid (`since` > `until`).
*/
fetchAllEvents<SeenOn extends boolean = false>(relayUrls: string[], filter: FetchFilter, timeRangeFilter: FetchTimeRangeFilter, options?: FetchAllOptions<SeenOn>): Promise<NostrEventExt<SeenOn>[]>;
/**
* Fetches latest events matching the filter from Nostr relays specified by the array of URLs.
*
* Events are sorted in "newest to oldest" order.
*
* Throws {@linkcode NostrFetchError} if `limit` is a non-positive number.
*/
fetchLatestEvents<SeenOn extends boolean = false>(relayUrls: string[], filter: FetchFilter, limit: number, options?: FetchLatestOptions<SeenOn>): Promise<NostrEventExt<SeenOn>[]>;
/**
* Fetches the last event matching the filter from Nostr relays specified by the array of URLs.
*
* Returns `undefined` if no event matching the filter exists in any relay.
*/
fetchLastEvent<SeenOn extends boolean = false>(relayUrls: string[], filter: FetchFilter, options?: FetchLatestOptions<SeenOn>): Promise<NostrEventExt<SeenOn> | undefined>;
/**
* Fetches latest up to `limit` events **for each key specified by `keyName` and `keysAndRelays`**.
*
* `keysAndRelays` can be either of two types:
*
* - `{ keys: K[], relayUrls: string[] }`: The fetcher will use the same relay set (`relayUrls`) for all `keys` to fetch events.
* - `Map<K, string[]>`: Key must be the key of event and value must be relay set for that key. The fetcher will use separate relay set for each key to fetch events.
*
* Result is an async iterable of `{ key: <key of events>, events: <events which have that key> }` pairs.
*
* Each array of events in the result are sorted in "newest to oldest" order.
*
* Throws {@linkcode NostrFetchError} if `limit` is a non-positive number.
*/
fetchLatestEventsPerKey<K extends FetchFilterKeyName, SeenOn extends boolean = false>(keyName: K, keysAndRelays: KeysAndRelays<K>, otherFilter: FetchFilter, limit: number, options?: FetchLatestOptions<SeenOn>): AsyncIterable<NostrEventListWithKey<K, SeenOn>>;
/**
* Fetches the last event **for each key specified by `keysAndRelays`**.
*
* `keysAndRelays` can be either of two types:
*
* - `{ keys: K[], relayUrls: string[] }`: The fetcher will use the same relay set (`relayUrls`) for all `keys` to fetch events.
* - `Map<K, string[]>`: Key must be key of the event and value must be relay set for that key. The fetcher will use separate relay set for each key to fetch events.
*
* Result is an async iterable of `{ key: <key of events>, event: <the latest event which have that key> }` pairs.
*
* `event` in result will be `undefined` if no event matching the filter exists in any relay.
*/
fetchLastEventPerKey<K extends FetchFilterKeyName, SeenOn extends boolean = false>(keyName: K, keysAndRelays: KeysAndRelays<K>, otherFilter: FetchFilter, options?: FetchLatestOptions<SeenOn>): AsyncIterable<NostrEventWithKey<K, SeenOn>>;
/**
* Fetches latest up to `limit` events **for each author specified by `authorsAndRelays`**.
*
* `authorsAndRelays` can be either of two types:
*
* - `{ authors: string[], relayUrls: string[] }`: The fetcher will use the same relay set (`relayUrls`) for all `authors` to fetch events.
* - `Map<string, string[]>`: Key must be author's pubkey and value must be relay set for that author. The fetcher will use separate relay set for each author to fetch events.
*
* Result is an async iterable of `{ author: <author's pubkey>, events: <events from the author> }` pairs.
*
* Each array of events in the result are sorted in "newest to oldest" order.
*
* Throws {@linkcode NostrFetchError} if `limit` is a non-positive number.
*
* Note: it's just an wrapper of `fetchLatestEventsPerKey`.
*/
fetchLatestEventsPerAuthor<SeenOn extends boolean = false>(authorsAndRelays: AuthorsAndRelays, otherFilter: Omit<FetchFilter, "authors">, limit: number, options?: FetchLatestOptions<SeenOn>): AsyncIterable<NostrEventListWithAuthor<SeenOn>>;
/**
* Fetches the last event **for each author specified by `authorsAndRelays`**.
*
* `authorsAndRelays` can be either of two types:
*
* - `{ authors: string[], relayUrls: string[] }`: The fetcher will use the same relay set (`relayUrls`) for all `authors` to fetch events.
* - `Map<string, string[]>`: Key must be author's pubkey and value must be relay set for that author. The fetcher will use separate relay set for each author to fetch events.
*
* Result is an async iterable of `{ author: <author's pubkey>, event: <the latest event from the author> }` pairs.
*
* `event` in result will be `undefined` if no event matching the filter for the author exists in any relay.
*
* Note: it's just a wrapper of `fetchLastEventPerKey`.
*/
fetchLastEventPerAuthor<SeenOn extends boolean = false>(authorsAndRelays: AuthorsAndRelays, otherFilter: Omit<FetchFilter, "authors">, options?: FetchLatestOptions<SeenOn>): AsyncIterable<NostrEventWithAuthor<SeenOn>>;
/**
* Cleans up all the internal states of the fetcher.
*/
shutdown(): void;
/**
* Enables [explicit resource management](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management) for `NostrFetcher` instances.
*
* If you bind a `NostrFetcher` instance to a variable with `using` keyword, it will be automatically shut down when the scope of the variable ends.
*/
[Symbol.dispose](): void;
}
export {};
//# sourceMappingURL=fetcher.d.ts.map