applesauce-core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +38 -0
  2. package/dist/event-store/event-store.d.ts +3 -1
  3. package/dist/event-store/event-store.js +6 -2
  4. package/dist/helpers/channel.d.ts +15 -0
  5. package/dist/helpers/channel.js +27 -0
  6. package/dist/helpers/event.d.ts +17 -1
  7. package/dist/helpers/event.js +22 -9
  8. package/dist/helpers/index.d.ts +2 -1
  9. package/dist/helpers/index.js +2 -1
  10. package/dist/helpers/json.d.ts +1 -0
  11. package/dist/helpers/json.js +8 -0
  12. package/dist/helpers/mailboxes.d.ts +10 -2
  13. package/dist/helpers/mailboxes.js +10 -9
  14. package/dist/helpers/mailboxes.test.d.ts +1 -0
  15. package/dist/helpers/mailboxes.test.js +80 -0
  16. package/dist/helpers/mute.d.ts +21 -0
  17. package/dist/helpers/mute.js +52 -0
  18. package/dist/helpers/pointers.d.ts +22 -0
  19. package/dist/helpers/pointers.js +127 -0
  20. package/dist/helpers/profile.d.ts +7 -0
  21. package/dist/helpers/profile.js +4 -4
  22. package/dist/helpers/relays.d.ts +6 -0
  23. package/dist/helpers/relays.js +7 -6
  24. package/dist/helpers/threading.d.ts +55 -0
  25. package/dist/helpers/threading.js +61 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +1 -0
  28. package/dist/observable/stateful.d.ts +1 -1
  29. package/dist/observable/stateful.js +1 -1
  30. package/dist/observable/throttle.d.ts +1 -0
  31. package/dist/observable/throttle.js +1 -0
  32. package/dist/promise/index.d.ts +1 -1
  33. package/dist/promise/index.js +1 -1
  34. package/dist/queries/channel.d.ts +11 -0
  35. package/dist/queries/channel.js +72 -0
  36. package/dist/queries/index.d.ts +7 -0
  37. package/dist/queries/index.js +7 -0
  38. package/dist/queries/mailboxes.d.ts +5 -0
  39. package/dist/queries/mailboxes.js +11 -0
  40. package/dist/queries/mute.d.ts +7 -0
  41. package/dist/queries/mute.js +16 -0
  42. package/dist/queries/profile.d.ts +3 -0
  43. package/dist/queries/profile.js +10 -0
  44. package/dist/queries/reactions.d.ts +4 -0
  45. package/dist/queries/reactions.js +19 -0
  46. package/dist/queries/simple.d.ts +5 -0
  47. package/dist/queries/simple.js +20 -0
  48. package/dist/queries/thread.d.ts +23 -0
  49. package/dist/queries/thread.js +65 -0
  50. package/dist/query-store/index.d.ts +35 -15
  51. package/dist/query-store/index.js +42 -57
  52. package/package.json +21 -2
  53. package/dist/helpers/symbols.d.ts +0 -17
  54. package/dist/helpers/symbols.js +0 -10
@@ -1,4 +1,10 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
+ export declare const SeenRelaysSymbol: unique symbol;
3
+ declare module "nostr-tools" {
4
+ interface Event {
5
+ [SeenRelaysSymbol]?: Set<string>;
6
+ }
7
+ }
2
8
  export declare function addSeenRelay(event: NostrEvent, relay: string): Set<string>;
3
9
  export declare function getSeenRelays(event: NostrEvent): Set<string> | undefined;
4
10
  export declare function validateRelayURL(relay: string | URL): URL;
@@ -1,12 +1,13 @@
1
- import { FromRelays } from "./symbols.js";
1
+ export const SeenRelaysSymbol = Symbol.for("seen-relays");
2
+ // Seen relays
2
3
  export function addSeenRelay(event, relay) {
3
- if (!event[FromRelays])
4
- event[FromRelays] = new Set();
5
- event[FromRelays].add(relay);
6
- return event[FromRelays];
4
+ if (!event[SeenRelaysSymbol])
5
+ event[SeenRelaysSymbol] = new Set();
6
+ event[SeenRelaysSymbol].add(relay);
7
+ return event[SeenRelaysSymbol];
7
8
  }
8
9
  export function getSeenRelays(event) {
9
- return event[FromRelays];
10
+ return event[SeenRelaysSymbol];
10
11
  }
11
12
  // Relay URLs
12
13
  export function validateRelayURL(relay) {
@@ -0,0 +1,55 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { AddressPointer, EventPointer } from "nostr-tools/nip19";
3
+ export type ThreadReferences = {
4
+ root?: {
5
+ e: EventPointer;
6
+ a: undefined;
7
+ } | {
8
+ e: undefined;
9
+ a: AddressPointer;
10
+ } | {
11
+ e: EventPointer;
12
+ a: AddressPointer;
13
+ };
14
+ reply?: {
15
+ e: EventPointer;
16
+ a: undefined;
17
+ } | {
18
+ e: undefined;
19
+ a: AddressPointer;
20
+ } | {
21
+ e: EventPointer;
22
+ a: AddressPointer;
23
+ };
24
+ };
25
+ export declare const Nip10ThreadRefsSymbol: unique symbol;
26
+ declare module "nostr-tools" {
27
+ interface Event {
28
+ [Nip10ThreadRefsSymbol]?: ThreadReferences;
29
+ }
30
+ }
31
+ /** Parses NIP-10 tags and handles legacy behavior */
32
+ export declare function interpretThreadTags(event: NostrEvent): {
33
+ root?: {
34
+ e: string[];
35
+ a: undefined;
36
+ } | {
37
+ e: undefined;
38
+ a: string[];
39
+ } | {
40
+ e: string[];
41
+ a: string[];
42
+ } | undefined;
43
+ reply?: {
44
+ e: string[];
45
+ a: undefined;
46
+ } | {
47
+ e: undefined;
48
+ a: string[];
49
+ } | {
50
+ e: string[];
51
+ a: string[];
52
+ } | undefined;
53
+ };
54
+ /** Returns the parsed NIP-10 tags for an event */
55
+ export declare function getNip10References(event: NostrEvent): ThreadReferences;
@@ -0,0 +1,61 @@
1
+ import { getAddressPointerFromTag, getEventPointerFromTag } from "./pointers.js";
2
+ export const Nip10ThreadRefsSymbol = Symbol.for("nip10-thread-refs");
3
+ /** Parses NIP-10 tags and handles legacy behavior */
4
+ export function interpretThreadTags(event) {
5
+ const eTags = event.tags.filter((t) => t[0] === "e" && t[1]);
6
+ const aTags = event.tags.filter((t) => t[0] === "a" && t[1]);
7
+ // find the root and reply tags.
8
+ let rootETag = eTags.find((t) => t[3] === "root");
9
+ let replyETag = eTags.find((t) => t[3] === "reply");
10
+ let rootATag = aTags.find((t) => t[3] === "root");
11
+ let replyATag = aTags.find((t) => t[3] === "reply");
12
+ if (!rootETag || !replyETag) {
13
+ // a direct reply does not need a "reply" reference
14
+ // https://github.com/nostr-protocol/nips/blob/master/10.md
15
+ // this is not necessarily to spec. but if there is only one id (root or reply) then assign it to both
16
+ // this handles the cases where a client only set a "reply" tag and no root
17
+ rootETag = replyETag = rootETag || replyETag;
18
+ }
19
+ if (!rootATag || !replyATag) {
20
+ rootATag = replyATag = rootATag || replyATag;
21
+ }
22
+ if (!rootETag && !replyETag) {
23
+ // legacy behavior
24
+ // https://github.com/nostr-protocol/nips/blob/master/10.md#positional-e-tags-deprecated
25
+ const legacyETags = eTags.filter((t) => {
26
+ // ignore it if there is a marker
27
+ if (t[3])
28
+ return false;
29
+ return true;
30
+ });
31
+ if (legacyETags.length >= 1) {
32
+ // first tag is the root
33
+ rootETag = legacyETags[0];
34
+ // last tag is reply
35
+ replyETag = legacyETags[legacyETags.length - 1] ?? rootETag;
36
+ }
37
+ }
38
+ return {
39
+ root: rootETag || rootATag ? { e: rootETag, a: rootATag } : undefined,
40
+ reply: replyETag || replyATag ? { e: replyETag, a: replyATag } : undefined,
41
+ };
42
+ }
43
+ /** Returns the parsed NIP-10 tags for an event */
44
+ export function getNip10References(event) {
45
+ let refs = event[Nip10ThreadRefsSymbol];
46
+ if (!refs) {
47
+ const e = event;
48
+ const tags = interpretThreadTags(e);
49
+ refs = event[Nip10ThreadRefsSymbol] = {
50
+ root: tags.root && {
51
+ e: tags.root.e && getEventPointerFromTag(tags.root.e),
52
+ a: tags.root.a && getAddressPointerFromTag(tags.root.a),
53
+ },
54
+ reply: tags.reply && {
55
+ e: tags.reply.e && getEventPointerFromTag(tags.reply.e),
56
+ a: tags.reply.a && getAddressPointerFromTag(tags.reply.a),
57
+ },
58
+ };
59
+ }
60
+ return refs;
61
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./event-store/index.js";
2
2
  export * from "./query-store/index.js";
3
3
  export * as helpers from "./helpers/index.js";
4
+ export * as Queries from "./queries/index.js";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./event-store/index.js";
2
2
  export * from "./query-store/index.js";
3
3
  export * as helpers from "./helpers/index.js";
4
+ export * as Queries from "./queries/index.js";
@@ -5,6 +5,6 @@ export type StatefulObservable<T> = Observable<T> & {
5
5
  error?: Error;
6
6
  complete?: boolean;
7
7
  };
8
- /** Wraps an observable and makes it stateful */
8
+ /** Wraps an {@link Observable} and makes it stateful */
9
9
  export declare function stateful<T extends unknown>(observable: Observable<T>, cleanup?: boolean): StatefulObservable<T>;
10
10
  export declare function isStateful<T extends unknown>(observable: Observable<T> | StatefulObservable<T>): observable is StatefulObservable<T>;
@@ -1,5 +1,5 @@
1
1
  import Observable from "zen-observable";
2
- /** Wraps an observable and makes it stateful */
2
+ /** Wraps an {@link Observable} and makes it stateful */
3
3
  export function stateful(observable, cleanup = false) {
4
4
  let subscription = undefined;
5
5
  let observers = [];
@@ -1,2 +1,3 @@
1
1
  import Observable from "zen-observable";
2
+ /** Throttles an {@link Observable} */
2
3
  export declare function throttle<T>(source: Observable<T>, interval: number): Observable<T>;
@@ -1,4 +1,5 @@
1
1
  import Observable from "zen-observable";
2
+ /** Throttles an {@link Observable} */
2
3
  export function throttle(source, interval) {
3
4
  return new Observable((observer) => {
4
5
  let lastEmissionTime = 0;
@@ -1 +1 @@
1
- export * from './deferred.js';
1
+ export * from "./deferred.js";
@@ -1 +1 @@
1
- export * from './deferred.js';
1
+ export * from "./deferred.js";
@@ -0,0 +1,11 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { Query } from "../query-store/index.js";
3
+ import { ChannelMetadataContent } from "../helpers/channel.js";
4
+ /** Creates a query that returns the latest parsed metadata */
5
+ export declare function ChannelMetadataQuery(channel: NostrEvent): Query<ChannelMetadataContent | undefined>;
6
+ /** Creates a query that returns a map of hidden messages Map<id, reason> */
7
+ export declare function ChannelHiddenQuery(channel: NostrEvent, authors?: string[]): Query<Map<string, string>>;
8
+ /** Creates a query that returns a map of muted users Map<pubkey, reason> */
9
+ export declare function ChannelMutedQuery(channel: NostrEvent, authors?: string[]): Query<Map<string, string>>;
10
+ /** Creates a query that returns all messages in a channel */
11
+ export declare function ChannelMessagesQuery(channel: NostrEvent): Query<NostrEvent[]>;
@@ -0,0 +1,72 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getChannelMetadataContent } from "../helpers/channel.js";
3
+ import { safeParse } from "../helpers/json.js";
4
+ /** Creates a query that returns the latest parsed metadata */
5
+ export function ChannelMetadataQuery(channel) {
6
+ return {
7
+ key: channel.id,
8
+ run: (events) => {
9
+ const filters = [
10
+ { ids: [channel.id] },
11
+ { kinds: [kinds.ChannelMetadata], "#e": [channel.id], authors: [channel.pubkey] },
12
+ ];
13
+ let latest = channel;
14
+ return events.stream(filters).map((event) => {
15
+ try {
16
+ if (event.pubkey === latest.pubkey && event.created_at > latest.created_at) {
17
+ latest = event;
18
+ }
19
+ return getChannelMetadataContent(latest);
20
+ }
21
+ catch (error) {
22
+ return undefined;
23
+ }
24
+ });
25
+ },
26
+ };
27
+ }
28
+ /** Creates a query that returns a map of hidden messages Map<id, reason> */
29
+ export function ChannelHiddenQuery(channel, authors = []) {
30
+ return {
31
+ key: channel.id,
32
+ run: (events) => {
33
+ const hidden = new Map();
34
+ return events
35
+ .stream([{ kinds: [kinds.ChannelHideMessage], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
36
+ .map((event) => {
37
+ const reason = safeParse(event.content)?.reason;
38
+ for (const tag of event.tags) {
39
+ if (tag[0] === "e" && tag[1])
40
+ hidden.set(tag[1], reason ?? "");
41
+ }
42
+ return hidden;
43
+ });
44
+ },
45
+ };
46
+ }
47
+ /** Creates a query that returns a map of muted users Map<pubkey, reason> */
48
+ export function ChannelMutedQuery(channel, authors = []) {
49
+ return {
50
+ key: channel.id + authors.join(","),
51
+ run: (events) => {
52
+ const muted = new Map();
53
+ return events
54
+ .stream([{ kinds: [kinds.ChannelMuteUser], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
55
+ .map((event) => {
56
+ const reason = safeParse(event.content)?.reason;
57
+ for (const tag of event.tags) {
58
+ if (tag[0] === "p" && tag[1])
59
+ muted.set(tag[1], reason ?? "");
60
+ }
61
+ return muted;
62
+ });
63
+ },
64
+ };
65
+ }
66
+ /** Creates a query that returns all messages in a channel */
67
+ export function ChannelMessagesQuery(channel) {
68
+ return {
69
+ key: channel.id,
70
+ run: (events) => events.timeline([{ kinds: [kinds.ChannelMessage], "#e": [channel.id] }]),
71
+ };
72
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./simple.js";
2
+ export * from "./profile.js";
3
+ export * from "./mailboxes.js";
4
+ export * from "./reactions.js";
5
+ export * from "./channel.js";
6
+ export * from "./mute.js";
7
+ export * from "./thread.js";
@@ -0,0 +1,7 @@
1
+ export * from "./simple.js";
2
+ export * from "./profile.js";
3
+ export * from "./mailboxes.js";
4
+ export * from "./reactions.js";
5
+ export * from "./channel.js";
6
+ export * from "./mute.js";
7
+ export * from "./thread.js";
@@ -0,0 +1,5 @@
1
+ import { Query } from "../query-store/index.js";
2
+ export declare function MailboxesQuery(pubkey: string): Query<{
3
+ inboxes: Set<string>;
4
+ outboxes: Set<string>;
5
+ } | undefined>;
@@ -0,0 +1,11 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getInboxes, getOutboxes } from "../helpers/mailboxes.js";
3
+ export function MailboxesQuery(pubkey) {
4
+ return {
5
+ key: pubkey,
6
+ run: (events) => events.replaceable(kinds.RelayList, pubkey).map((event) => event && {
7
+ inboxes: getInboxes(event),
8
+ outboxes: getOutboxes(event),
9
+ }),
10
+ };
11
+ }
@@ -0,0 +1,7 @@
1
+ import { Query } from "../query-store/index.js";
2
+ export declare function UserMuteQuery(pubkey: string): Query<{
3
+ words: Set<string>;
4
+ pubkeys: Set<string>;
5
+ threads: Set<string>;
6
+ hashtags: Set<string>;
7
+ } | undefined>;
@@ -0,0 +1,16 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getMutedHashtags, getMutedPubkeys, getMutedThreads, getMutedWords } from "../helpers/mute.js";
3
+ export function UserMuteQuery(pubkey) {
4
+ return {
5
+ key: pubkey,
6
+ run: (store) => store.replaceable(kinds.Mutelist, pubkey).map((event) => {
7
+ if (!event)
8
+ return;
9
+ const pubkeys = getMutedPubkeys(event);
10
+ const threads = getMutedThreads(event);
11
+ const hashtags = getMutedHashtags(event);
12
+ const words = getMutedWords(event);
13
+ return { pubkeys, threads, hashtags, words };
14
+ }),
15
+ };
16
+ }
@@ -0,0 +1,3 @@
1
+ import { ProfileContent } from "../helpers/profile.js";
2
+ import { Query } from "../query-store/index.js";
3
+ export declare function ProfileQuery(pubkey: string): Query<ProfileContent | undefined>;
@@ -0,0 +1,10 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getProfileContent } from "../helpers/profile.js";
3
+ export function ProfileQuery(pubkey) {
4
+ return {
5
+ key: pubkey,
6
+ run: (events) => {
7
+ return events.replaceable(kinds.Metadata, pubkey).map((event) => event && getProfileContent(event));
8
+ },
9
+ };
10
+ }
@@ -0,0 +1,4 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { Query } from "../query-store/index.js";
3
+ /** Creates a query that returns all reactions to an event (supports replaceable events) */
4
+ export declare function ReactionsQuery(event: NostrEvent): Query<NostrEvent[]>;
@@ -0,0 +1,19 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getEventUID, isReplaceable } from "../helpers/event.js";
3
+ /** Creates a query that returns all reactions to an event (supports replaceable events) */
4
+ export function ReactionsQuery(event) {
5
+ return {
6
+ key: getEventUID(event),
7
+ run: (events) => events.timeline(isReplaceable(event.kind)
8
+ ? [
9
+ { kinds: [kinds.Reaction], "#e": [event.id] },
10
+ { kinds: [kinds.Reaction], "#a": [getEventUID(event)] },
11
+ ]
12
+ : [
13
+ {
14
+ kinds: [kinds.Reaction],
15
+ "#e": [event.id],
16
+ },
17
+ ]),
18
+ };
19
+ }
@@ -0,0 +1,5 @@
1
+ import { Filter, NostrEvent } from "nostr-tools";
2
+ import { Query } from "../query-store/index.js";
3
+ export declare function SingleEventQuery(uid: string): Query<NostrEvent | undefined>;
4
+ export declare function ReplaceableQuery(kind: number, pubkey: string, d?: string): Query<NostrEvent | undefined>;
5
+ export declare function TimelineQuery(filters: Filter | Filter[]): Query<NostrEvent[]>;
@@ -0,0 +1,20 @@
1
+ import stringify from "json-stringify-deterministic";
2
+ import { getReplaceableUID } from "../helpers/event.js";
3
+ export function SingleEventQuery(uid) {
4
+ return {
5
+ key: uid,
6
+ run: (events) => events.event(uid),
7
+ };
8
+ }
9
+ export function ReplaceableQuery(kind, pubkey, d) {
10
+ return {
11
+ key: getReplaceableUID(kind, pubkey, d),
12
+ run: (events) => events.replaceable(kind, pubkey, d),
13
+ };
14
+ }
15
+ export function TimelineQuery(filters) {
16
+ return {
17
+ key: stringify(filters),
18
+ run: (events) => events.timeline(Array.isArray(filters) ? filters : [filters]),
19
+ };
20
+ }
@@ -0,0 +1,23 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { AddressPointer, EventPointer } from "nostr-tools/nip19";
3
+ import { Query } from "../query-store/index.js";
4
+ import { ThreadReferences } from "../helpers/threading.js";
5
+ export type Thread = {
6
+ root?: ThreadItem;
7
+ all: Map<string, ThreadItem>;
8
+ };
9
+ export type ThreadItem = {
10
+ /** underlying nostr event */
11
+ event: NostrEvent;
12
+ refs: ThreadReferences;
13
+ /** the thread root, according to this event */
14
+ root?: ThreadItem;
15
+ /** the parent event this is replying to */
16
+ parent?: ThreadItem;
17
+ /** direct child replies */
18
+ replies: Set<ThreadItem>;
19
+ };
20
+ export type ThreadQueryOptions = {
21
+ kinds?: number[];
22
+ };
23
+ export declare function ThreadQuery(root: string | AddressPointer | EventPointer, opts?: ThreadQueryOptions): Query<Thread>;
@@ -0,0 +1,65 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getNip10References } from "../helpers/threading.js";
3
+ import { getCoordinateFromAddressPointer, isAddressPointer } from "../helpers/pointers.js";
4
+ import { getEventUID } from "../helpers/event.js";
5
+ const defaultOptions = {
6
+ kinds: [kinds.ShortTextNote],
7
+ };
8
+ export function ThreadQuery(root, opts) {
9
+ const parentReferences = new Map();
10
+ const items = new Map();
11
+ const { kinds } = { ...defaultOptions, ...opts };
12
+ let rootUID = "";
13
+ const rootFilter = {};
14
+ const replyFilter = { kinds };
15
+ if (isAddressPointer(root)) {
16
+ rootUID = getCoordinateFromAddressPointer(root);
17
+ rootFilter.kinds = [root.kind];
18
+ rootFilter.authors = [root.pubkey];
19
+ rootFilter["#d"] = [root.identifier];
20
+ replyFilter["#a"] = [rootUID];
21
+ }
22
+ else if (typeof root === "string") {
23
+ rootUID = root;
24
+ rootFilter.ids = [root];
25
+ replyFilter["#e"] = [root];
26
+ }
27
+ else {
28
+ rootUID = root.id;
29
+ rootFilter.ids = [root.id];
30
+ replyFilter["#e"] = [root.id];
31
+ }
32
+ return {
33
+ key: `${rootUID}-${kinds.join(",")}`,
34
+ run: (events) => events.stream([rootFilter, replyFilter]).map((event) => {
35
+ if (!items.has(getEventUID(event))) {
36
+ const refs = getNip10References(event);
37
+ const replies = parentReferences.get(getEventUID(event)) || new Set();
38
+ const item = { event, refs, replies };
39
+ for (const child of replies) {
40
+ child.parent = item;
41
+ }
42
+ // add item to parent
43
+ if (refs.reply?.e || refs.reply?.a) {
44
+ let uid = refs.reply.e ? refs.reply.e.id : getCoordinateFromAddressPointer(refs.reply.a);
45
+ item.parent = items.get(uid);
46
+ if (item.parent) {
47
+ item.parent.replies.add(item);
48
+ }
49
+ else {
50
+ // parent isn't created yet, store ref for later
51
+ let set = parentReferences.get(uid);
52
+ if (!set) {
53
+ set = new Set();
54
+ parentReferences.set(uid, set);
55
+ }
56
+ set.add(item);
57
+ }
58
+ }
59
+ // add item to map
60
+ items.set(getEventUID(event), item);
61
+ }
62
+ return { root: items.get(rootUID), all: items };
63
+ }),
64
+ };
65
+ }
@@ -1,26 +1,46 @@
1
1
  import Observable from "zen-observable";
2
2
  import { Filter, NostrEvent } from "nostr-tools";
3
3
  import { EventStore } from "../event-store/event-store.js";
4
- import { ProfileContent } from "../helpers/profile.js";
5
4
  import { LRU } from "../utils/lru.js";
5
+ import * as Queries from "../queries/index.js";
6
+ import { AddressPointer, EventPointer } from "nostr-tools/nip19";
7
+ export type Query<T extends unknown> = {
8
+ key: string;
9
+ run: (events: EventStore, store: QueryStore) => Observable<T>;
10
+ };
11
+ export type QueryConstructor<T extends unknown, Args extends Array<any>> = (...args: Args) => Query<T>;
6
12
  export declare class QueryStore {
13
+ static Queries: typeof Queries;
7
14
  store: EventStore;
8
15
  constructor(store: EventStore);
9
- singleEvents: LRU<Observable<import("nostr-tools").Event | undefined>>;
10
- getEvent(id: string): Observable<import("nostr-tools").Event | undefined>;
11
- getReplaceable(kind: number, pubkey: string, d?: string): Observable<import("nostr-tools").Event | undefined>;
12
- timelines: LRU<Observable<import("nostr-tools").Event[]>>;
13
- getTimeline(filters: Filter[]): Observable<import("nostr-tools").Event[]>;
14
- profiles: LRU<Observable<ProfileContent | undefined>>;
15
- getProfile(pubkey: string): Observable<ProfileContent | undefined>;
16
- reactions: LRU<Observable<import("nostr-tools").Event[]>>;
17
- getReactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
18
- mailboxes: LRU<Observable<{
19
- inboxes: Set<string>;
20
- outboxes: Set<string>;
21
- } | undefined>>;
22
- getMailboxes(pubkey: string): Observable<{
16
+ queries: LRU<Observable<any>>;
17
+ /** Creates a cached query */
18
+ runQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => {
19
+ key: string;
20
+ run: (events: EventStore, store: QueryStore) => Observable<T>;
21
+ }): (...args: Args) => Observable<T>;
22
+ /** Returns a single event */
23
+ event(id: string): Observable<import("nostr-tools").Event | undefined>;
24
+ /** Returns the latest version of a replaceable event */
25
+ replaceable(kind: number, pubkey: string, d?: string): Observable<import("nostr-tools").Event | undefined>;
26
+ /** Returns an array of events that match the filter */
27
+ timeline(filters: Filter | Filter[]): Observable<import("nostr-tools").Event[]>;
28
+ /** Returns the parsed profile (0) for a pubkey */
29
+ profile(pubkey: string): Observable<import("../helpers/profile.js").ProfileContent | undefined>;
30
+ /** Returns all reactions for an event (supports replaceable events) */
31
+ reactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
32
+ /** Returns the parsed relay list (10002) for the pubkey */
33
+ mailboxes(pubkey: string): Observable<{
23
34
  inboxes: Set<string>;
24
35
  outboxes: Set<string>;
25
36
  } | undefined>;
37
+ /** Returns the parsed mute list for the pubkey */
38
+ mute(pubkey: string): Observable<{
39
+ words: Set<string>;
40
+ pubkeys: Set<string>;
41
+ threads: Set<string>;
42
+ hashtags: Set<string>;
43
+ } | undefined>;
44
+ thread(root: string | EventPointer | AddressPointer): Observable<Queries.Thread>;
26
45
  }
46
+ export { Queries };