applesauce-core 0.12.1 → 1.0.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.
- package/README.md +28 -10
- package/dist/event-store/__tests__/event-store.test.js +52 -1
- package/dist/event-store/database.js +3 -3
- package/dist/event-store/event-store.js +15 -8
- package/dist/event-store/interface.d.ts +11 -7
- package/dist/helpers/__tests__/bookmarks.test.d.ts +1 -0
- package/dist/helpers/__tests__/bookmarks.test.js +88 -0
- package/dist/helpers/__tests__/comment.test.js +14 -0
- package/dist/helpers/__tests__/contacts.test.d.ts +1 -0
- package/dist/helpers/__tests__/contacts.test.js +34 -0
- package/dist/helpers/__tests__/events.test.d.ts +1 -0
- package/dist/helpers/__tests__/events.test.js +32 -0
- package/dist/helpers/__tests__/mutes.test.d.ts +1 -0
- package/dist/helpers/__tests__/mutes.test.js +55 -0
- package/dist/helpers/bookmarks.d.ts +6 -1
- package/dist/helpers/bookmarks.js +52 -7
- package/dist/helpers/comment.d.ts +7 -3
- package/dist/helpers/comment.js +6 -1
- package/dist/helpers/contacts.d.ts +11 -0
- package/dist/helpers/contacts.js +34 -0
- package/dist/helpers/event.d.ts +8 -3
- package/dist/helpers/event.js +21 -13
- package/dist/helpers/lists.d.ts +40 -12
- package/dist/helpers/lists.js +62 -23
- package/dist/helpers/mutes.d.ts +8 -0
- package/dist/helpers/mutes.js +66 -5
- package/dist/helpers/nip-19.d.ts +14 -0
- package/dist/helpers/nip-19.js +29 -0
- package/dist/helpers/pointers.js +6 -6
- package/dist/observable/__tests__/listen-latest-updates.test.d.ts +1 -0
- package/dist/observable/__tests__/listen-latest-updates.test.js +55 -0
- package/dist/observable/defined.d.ts +3 -0
- package/dist/observable/defined.js +5 -0
- package/dist/observable/get-observable-value.d.ts +4 -1
- package/dist/observable/get-observable-value.js +4 -1
- package/dist/observable/index.d.ts +3 -1
- package/dist/observable/index.js +3 -1
- package/dist/observable/listen-latest-updates.d.ts +5 -0
- package/dist/observable/listen-latest-updates.js +12 -0
- package/dist/queries/blossom.js +1 -6
- package/dist/queries/bookmarks.d.ts +5 -5
- package/dist/queries/bookmarks.js +18 -17
- package/dist/queries/channels.js +41 -53
- package/dist/queries/comments.js +6 -9
- package/dist/queries/contacts.d.ts +6 -1
- package/dist/queries/contacts.js +21 -9
- package/dist/queries/index.d.ts +1 -0
- package/dist/queries/index.js +1 -0
- package/dist/queries/mailboxes.js +4 -7
- package/dist/queries/mutes.d.ts +6 -6
- package/dist/queries/mutes.js +20 -19
- package/dist/queries/pins.d.ts +1 -0
- package/dist/queries/pins.js +4 -6
- package/dist/queries/profile.js +1 -6
- package/dist/queries/reactions.js +11 -14
- package/dist/queries/relays.d.ts +27 -0
- package/dist/queries/relays.js +44 -0
- package/dist/queries/simple.js +5 -22
- package/dist/queries/thread.js +45 -51
- package/dist/queries/user-status.js +23 -29
- package/dist/queries/zaps.js +10 -13
- package/dist/query-store/query-store.d.ts +7 -6
- package/dist/query-store/query-store.js +13 -8
- package/package.json +3 -3
- package/dist/observable/share-latest-value.d.ts +0 -6
- package/dist/observable/share-latest-value.js +0 -24
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
|
-
import { getAddressPointerFromATag, getEventPointerFromETag } from "./pointers.js";
|
|
3
2
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
4
|
-
import { getHiddenTags } from "./index.js";
|
|
3
|
+
import { getHiddenTags, isHiddenTagsLocked } from "./index.js";
|
|
4
|
+
import { mergeAddressPointers, mergeEventPointers } from "./nip-19.js";
|
|
5
|
+
import { getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag } from "./pointers.js";
|
|
5
6
|
export const BookmarkPublicSymbol = Symbol.for("bookmark-public");
|
|
6
7
|
export const BookmarkHiddenSymbol = Symbol.for("bookmark-hidden");
|
|
8
|
+
/** Parses an array of tags into a {@link Bookmarks} object */
|
|
7
9
|
export function parseBookmarkTags(tags) {
|
|
8
10
|
const notes = tags.filter((t) => t[0] === "e" && t[1]).map(getEventPointerFromETag);
|
|
9
11
|
const articles = tags
|
|
@@ -14,14 +16,57 @@ export function parseBookmarkTags(tags) {
|
|
|
14
16
|
const urls = tags.filter((t) => t[0] === "r" && t[1]).map((t) => t[1]);
|
|
15
17
|
return { notes, articles, hashtags, urls };
|
|
16
18
|
}
|
|
17
|
-
/**
|
|
19
|
+
/** Merges any number of {@link Bookmarks} objects */
|
|
20
|
+
export function mergeBookmarks(...bookmarks) {
|
|
21
|
+
const notes = new Map();
|
|
22
|
+
const articles = new Map();
|
|
23
|
+
const hashtags = new Set();
|
|
24
|
+
const urls = new Set();
|
|
25
|
+
for (const bookmark of bookmarks) {
|
|
26
|
+
if (!bookmark)
|
|
27
|
+
continue;
|
|
28
|
+
for (const note of bookmark.notes) {
|
|
29
|
+
const existing = notes.get(note.id);
|
|
30
|
+
if (existing)
|
|
31
|
+
notes.set(note.id, mergeEventPointers(existing, note));
|
|
32
|
+
else
|
|
33
|
+
notes.set(note.id, note);
|
|
34
|
+
}
|
|
35
|
+
for (const article of bookmark.articles) {
|
|
36
|
+
const coord = getCoordinateFromAddressPointer(article);
|
|
37
|
+
const existing = articles.get(coord);
|
|
38
|
+
if (existing)
|
|
39
|
+
articles.set(coord, mergeAddressPointers(existing, article));
|
|
40
|
+
else
|
|
41
|
+
articles.set(coord, article);
|
|
42
|
+
}
|
|
43
|
+
for (const hashtag of bookmark.hashtags)
|
|
44
|
+
hashtags.add(hashtag);
|
|
45
|
+
for (const url of bookmark.urls)
|
|
46
|
+
urls.add(url);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
notes: Array.from(notes.values()),
|
|
50
|
+
articles: Array.from(articles.values()),
|
|
51
|
+
hashtags: Array.from(hashtags),
|
|
52
|
+
urls: Array.from(urls),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Returns all the bookmarks of the event */
|
|
18
56
|
export function getBookmarks(bookmark) {
|
|
57
|
+
const hidden = getHiddenBookmarks(bookmark);
|
|
58
|
+
if (hidden)
|
|
59
|
+
return mergeBookmarks(hidden, getPublicBookmarks(bookmark));
|
|
60
|
+
else
|
|
61
|
+
return getPublicBookmarks(bookmark);
|
|
62
|
+
}
|
|
63
|
+
/** Returns the public bookmarks of the event */
|
|
64
|
+
export function getPublicBookmarks(bookmark) {
|
|
19
65
|
return getOrComputeCachedValue(bookmark, BookmarkPublicSymbol, () => parseBookmarkTags(bookmark.tags));
|
|
20
66
|
}
|
|
21
67
|
/** Returns the bookmarks of the event if its unlocked */
|
|
22
68
|
export function getHiddenBookmarks(bookmark) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
69
|
+
if (isHiddenTagsLocked(bookmark))
|
|
70
|
+
return undefined;
|
|
71
|
+
return getOrComputeCachedValue(bookmark, BookmarkHiddenSymbol, () => parseBookmarkTags(getHiddenTags(bookmark)));
|
|
27
72
|
}
|
|
@@ -2,20 +2,24 @@ import { NostrEvent } from "nostr-tools";
|
|
|
2
2
|
import { ExternalPointer, ExternalIdentifiers } from "./external-id.js";
|
|
3
3
|
export declare const COMMENT_KIND = 1111;
|
|
4
4
|
export type CommentEventPointer = {
|
|
5
|
+
type: "event";
|
|
5
6
|
id: string;
|
|
6
7
|
kind: number;
|
|
7
8
|
pubkey?: string;
|
|
8
9
|
relay?: string;
|
|
9
10
|
};
|
|
10
11
|
export type CommentAddressPointer = {
|
|
12
|
+
type: "address";
|
|
11
13
|
id?: string;
|
|
12
14
|
kind: number;
|
|
13
15
|
pubkey: string;
|
|
14
16
|
identifier: string;
|
|
15
17
|
relay?: string;
|
|
16
18
|
};
|
|
17
|
-
export type CommentExternalPointer = ExternalPointer<
|
|
18
|
-
|
|
19
|
+
export type CommentExternalPointer<T extends keyof ExternalIdentifiers> = ExternalPointer<T> & {
|
|
20
|
+
type: "external";
|
|
21
|
+
};
|
|
22
|
+
export type CommentPointer = CommentEventPointer | CommentAddressPointer | CommentExternalPointer<keyof ExternalIdentifiers>;
|
|
19
23
|
export declare const CommentRootPointerSymbol: unique symbol;
|
|
20
24
|
export declare const CommentReplyPointerSymbol: unique symbol;
|
|
21
25
|
/**
|
|
@@ -32,7 +36,7 @@ export declare function getCommentAddressPointer(tags: string[][], root?: boolea
|
|
|
32
36
|
* Gets the ExternalPointer from an array of tags
|
|
33
37
|
* @throws
|
|
34
38
|
*/
|
|
35
|
-
export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer | null;
|
|
39
|
+
export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer<keyof ExternalIdentifiers> | null;
|
|
36
40
|
/**
|
|
37
41
|
* Returns the root pointer for a comment
|
|
38
42
|
* @throws
|
package/dist/helpers/comment.js
CHANGED
|
@@ -18,6 +18,7 @@ export function getCommentEventPointer(tags, root = false) {
|
|
|
18
18
|
// only the root pubkey can be gotten from the tags, since due to quotes and mentions there will be many "p" tags for replies
|
|
19
19
|
const rootPubkey = root ? tags.find((t) => t[0] === "P")?.[1] : undefined;
|
|
20
20
|
const pointer = {
|
|
21
|
+
type: "event",
|
|
21
22
|
id: eTag[1],
|
|
22
23
|
kind: parseInt(kind),
|
|
23
24
|
pubkey: eTag[3] || rootPubkey || undefined,
|
|
@@ -40,6 +41,7 @@ export function getCommentAddressPointer(tags, root = false) {
|
|
|
40
41
|
throw new Error("Missing kind tag");
|
|
41
42
|
const addressPointer = getAddressPointerFromATag(aTag);
|
|
42
43
|
const pointer = {
|
|
44
|
+
type: "address",
|
|
43
45
|
id: eTag?.[1],
|
|
44
46
|
pubkey: addressPointer.pubkey,
|
|
45
47
|
identifier: addressPointer.identifier,
|
|
@@ -60,7 +62,10 @@ export function getCommentExternalPointer(tags, root = false) {
|
|
|
60
62
|
if (iTag) {
|
|
61
63
|
if (!kind)
|
|
62
64
|
throw new Error("Missing kind tag");
|
|
63
|
-
return
|
|
65
|
+
return {
|
|
66
|
+
type: "external",
|
|
67
|
+
...getExternalPointerFromTag(iTag),
|
|
68
|
+
};
|
|
64
69
|
}
|
|
65
70
|
return null;
|
|
66
71
|
}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
import { ProfilePointer } from "nostr-tools/nip19";
|
|
2
3
|
export declare const ContactsRelaysSymbol: unique symbol;
|
|
4
|
+
export declare const PublicContactsSymbol: unique symbol;
|
|
5
|
+
export declare const HiddenContactsSymbol: unique symbol;
|
|
3
6
|
export declare function getRelaysFromContactsEvent(event: NostrEvent): Map<string, "all" | "inbox" | "outbox"> | null;
|
|
7
|
+
/** Merges any number of contact lists into a single list */
|
|
8
|
+
export declare function mergeContacts(...pointers: (ProfilePointer | undefined | (ProfilePointer | undefined)[])[]): ProfilePointer[];
|
|
9
|
+
/** Returns all public and hidden contacts from a contacts list event */
|
|
10
|
+
export declare function getContacts(event: NostrEvent): ProfilePointer[];
|
|
11
|
+
/** Returns only the public contacts from a contacts list event */
|
|
12
|
+
export declare function getPublicContacts(event: NostrEvent): ProfilePointer[];
|
|
13
|
+
/** Returns only the hidden contacts from a contacts list event */
|
|
14
|
+
export declare function getHiddenContacts(event: NostrEvent): ProfilePointer[] | undefined;
|
package/dist/helpers/contacts.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
2
|
import { isSafeRelayURL } from "./relays.js";
|
|
3
|
+
import { isPTag, processTags } from "./tags.js";
|
|
4
|
+
import { getProfilePointerFromPTag } from "./pointers.js";
|
|
5
|
+
import { getHiddenTags, isHiddenTagsLocked } from "./hidden-tags.js";
|
|
3
6
|
export const ContactsRelaysSymbol = Symbol.for("contacts-relays");
|
|
7
|
+
export const PublicContactsSymbol = Symbol.for("public-contacts");
|
|
8
|
+
export const HiddenContactsSymbol = Symbol.for("hidden-contacts");
|
|
4
9
|
export function getRelaysFromContactsEvent(event) {
|
|
5
10
|
return getOrComputeCachedValue(event, ContactsRelaysSymbol, () => {
|
|
6
11
|
try {
|
|
@@ -23,3 +28,32 @@ export function getRelaysFromContactsEvent(event) {
|
|
|
23
28
|
}
|
|
24
29
|
});
|
|
25
30
|
}
|
|
31
|
+
/** Merges any number of contact lists into a single list */
|
|
32
|
+
export function mergeContacts(...pointers) {
|
|
33
|
+
const merged = new Map();
|
|
34
|
+
for (const arr of pointers) {
|
|
35
|
+
if (Array.isArray(arr)) {
|
|
36
|
+
for (const pointer of arr)
|
|
37
|
+
if (pointer)
|
|
38
|
+
merged.set(pointer.pubkey, pointer);
|
|
39
|
+
}
|
|
40
|
+
else if (arr) {
|
|
41
|
+
merged.set(arr.pubkey, arr);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Array.from(merged.values());
|
|
45
|
+
}
|
|
46
|
+
/** Returns all public and hidden contacts from a contacts list event */
|
|
47
|
+
export function getContacts(event) {
|
|
48
|
+
return mergeContacts(getPublicContacts(event), getHiddenContacts(event));
|
|
49
|
+
}
|
|
50
|
+
/** Returns only the public contacts from a contacts list event */
|
|
51
|
+
export function getPublicContacts(event) {
|
|
52
|
+
return getOrComputeCachedValue(event, PublicContactsSymbol, () => processTags(event.tags, (t) => (isPTag(t) ? t : undefined), getProfilePointerFromPTag));
|
|
53
|
+
}
|
|
54
|
+
/** Returns only the hidden contacts from a contacts list event */
|
|
55
|
+
export function getHiddenContacts(event) {
|
|
56
|
+
if (isHiddenTagsLocked(event))
|
|
57
|
+
return undefined;
|
|
58
|
+
return getOrComputeCachedValue(event, HiddenContactsSymbol, () => processTags(getHiddenTags(event), (t) => (isPTag(t) ? t : undefined), getProfilePointerFromPTag));
|
|
59
|
+
}
|
package/dist/helpers/event.d.ts
CHANGED
|
@@ -24,11 +24,16 @@ export declare function isReplaceable(kind: number): boolean;
|
|
|
24
24
|
/**
|
|
25
25
|
* Returns the events Unique ID
|
|
26
26
|
* For normal or ephemeral events this is ( event.id )
|
|
27
|
-
* For replaceable events this is ( event.kind + ":" + event.pubkey )
|
|
28
|
-
* For parametrized replaceable events this is ( event.kind + ":" + event.pubkey + ":" + event.tags.d
|
|
27
|
+
* For replaceable events this is ( event.kind + ":" + event.pubkey + ":" )
|
|
28
|
+
* For parametrized replaceable events this is ( event.kind + ":" + event.pubkey + ":" + event.tags.d )
|
|
29
29
|
*/
|
|
30
30
|
export declare function getEventUID(event: NostrEvent): string;
|
|
31
|
-
|
|
31
|
+
/** Returns the replaceable event address for an addressable event */
|
|
32
|
+
export declare function getReplaceableAddress(event: NostrEvent): string;
|
|
33
|
+
/** Creates a replaceable event address from a kind, pubkey, and identifier */
|
|
34
|
+
export declare function createReplaceableAddress(kind: number, pubkey: string, identifier?: string): string;
|
|
35
|
+
/** @deprecated use createReplaceableAddress instead */
|
|
36
|
+
export declare const getReplaceableUID: typeof createReplaceableAddress;
|
|
32
37
|
/** Returns a Set of tag names and values that are indexable */
|
|
33
38
|
export declare function getIndexableTags(event: NostrEvent): Set<string>;
|
|
34
39
|
/**
|
package/dist/helpers/event.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { verifiedSymbol } from "nostr-tools";
|
|
2
2
|
import { INDEXABLE_TAGS } from "../event-store/common.js";
|
|
3
3
|
import { getHiddenTags } from "./hidden-tags.js";
|
|
4
4
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
5
|
-
import {
|
|
5
|
+
import { isAddressableKind, isReplaceableKind } from "nostr-tools/kinds";
|
|
6
6
|
import { EventStoreSymbol } from "../event-store/event-store.js";
|
|
7
7
|
export const EventUIDSymbol = Symbol.for("event-uid");
|
|
8
8
|
export const EventIndexableTagsSymbol = Symbol.for("indexable-tags");
|
|
@@ -29,30 +29,38 @@ export function isEvent(event) {
|
|
|
29
29
|
* or parameterized replaceable ( 30000 <= n < 40000 )
|
|
30
30
|
*/
|
|
31
31
|
export function isReplaceable(kind) {
|
|
32
|
-
return
|
|
32
|
+
return isReplaceableKind(kind) || isAddressableKind(kind);
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* Returns the events Unique ID
|
|
36
36
|
* For normal or ephemeral events this is ( event.id )
|
|
37
|
-
* For replaceable events this is ( event.kind + ":" + event.pubkey )
|
|
38
|
-
* For parametrized replaceable events this is ( event.kind + ":" + event.pubkey + ":" + event.tags.d
|
|
37
|
+
* For replaceable events this is ( event.kind + ":" + event.pubkey + ":" )
|
|
38
|
+
* For parametrized replaceable events this is ( event.kind + ":" + event.pubkey + ":" + event.tags.d )
|
|
39
39
|
*/
|
|
40
40
|
export function getEventUID(event) {
|
|
41
41
|
let uid = event[EventUIDSymbol];
|
|
42
42
|
if (!uid) {
|
|
43
|
-
if (isReplaceable(event.kind))
|
|
44
|
-
|
|
45
|
-
uid = getReplaceableUID(event.kind, event.pubkey, d);
|
|
46
|
-
}
|
|
43
|
+
if (isReplaceable(event.kind))
|
|
44
|
+
uid = getReplaceableAddress(event);
|
|
47
45
|
else
|
|
48
46
|
uid = event.id;
|
|
49
47
|
event[EventUIDSymbol] = uid;
|
|
50
48
|
}
|
|
51
49
|
return uid;
|
|
52
50
|
}
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
/** Returns the replaceable event address for an addressable event */
|
|
52
|
+
export function getReplaceableAddress(event) {
|
|
53
|
+
if (!isReplaceable(event.kind))
|
|
54
|
+
throw new Error("Event is not replaceable or addressable");
|
|
55
|
+
const identifier = isAddressableKind(event.kind) ? getReplaceableIdentifier(event) : undefined;
|
|
56
|
+
return createReplaceableAddress(event.kind, event.pubkey, identifier);
|
|
57
|
+
}
|
|
58
|
+
/** Creates a replaceable event address from a kind, pubkey, and identifier */
|
|
59
|
+
export function createReplaceableAddress(kind, pubkey, identifier) {
|
|
60
|
+
return kind + ":" + pubkey + ":" + (identifier ?? "");
|
|
55
61
|
}
|
|
62
|
+
/** @deprecated use createReplaceableAddress instead */
|
|
63
|
+
export const getReplaceableUID = createReplaceableAddress;
|
|
56
64
|
/** Returns a Set of tag names and values that are indexable */
|
|
57
65
|
export function getIndexableTags(event) {
|
|
58
66
|
let indexable = event[EventIndexableTagsSymbol];
|
|
@@ -100,8 +108,8 @@ export function getParentEventStore(event) {
|
|
|
100
108
|
* @throws
|
|
101
109
|
*/
|
|
102
110
|
export function getReplaceableIdentifier(event) {
|
|
103
|
-
if (!
|
|
104
|
-
throw new Error("Event is not
|
|
111
|
+
if (!isAddressableKind(event.kind))
|
|
112
|
+
throw new Error("Event is not addressable");
|
|
105
113
|
return getOrComputeCachedValue(event, ReplaceableIdentifierSymbol, () => {
|
|
106
114
|
const d = getTagValue(event, "d");
|
|
107
115
|
if (d === undefined)
|
package/dist/helpers/lists.d.ts
CHANGED
|
@@ -1,28 +1,56 @@
|
|
|
1
1
|
import { AddressPointer, EventPointer, ProfilePointer } from "nostr-tools/nip19";
|
|
2
2
|
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
export declare const FAVORITE_RELAYS_KIND = 10012;
|
|
4
|
+
export type ReadListTags = "public" | "hidden" | "all";
|
|
5
|
+
/** Returns all the tags of a list or set */
|
|
6
|
+
export declare function getListTags(list: NostrEvent, type?: ReadListTags): string[][];
|
|
3
7
|
/**
|
|
4
8
|
* Checks if an event pointer is anywhere in a list or set
|
|
5
9
|
* NOTE: Ignores the `relay` field in EventPointer
|
|
6
|
-
*
|
|
10
|
+
* @param list - The list or set to check
|
|
11
|
+
* @param pointer - The event pointer to check
|
|
12
|
+
* @param type - Which types of tags to check
|
|
7
13
|
*/
|
|
8
|
-
export declare function isEventPointerInList(list: NostrEvent, pointer: string | EventPointer): boolean;
|
|
14
|
+
export declare function isEventPointerInList(list: NostrEvent, pointer: string | EventPointer, type?: ReadListTags): boolean;
|
|
9
15
|
/**
|
|
10
16
|
* Checks if an address pointer is anywhere in a list or set
|
|
11
17
|
* NOTE: Ignores the `relay` field in AddressPointer
|
|
12
|
-
*
|
|
18
|
+
* @param list - The list or set to check
|
|
19
|
+
* @param pointer - The address pointer to check
|
|
20
|
+
* @param type - Which types of tags to check
|
|
13
21
|
*/
|
|
14
|
-
export declare function isAddressPointerInList(list: NostrEvent, pointer: string | AddressPointer): boolean;
|
|
22
|
+
export declare function isAddressPointerInList(list: NostrEvent, pointer: string | AddressPointer, type?: ReadListTags): boolean;
|
|
15
23
|
/**
|
|
16
24
|
* Checks if an profile pointer is anywhere in a list or set
|
|
17
25
|
* NOTE: Ignores the `relay` field in ProfilePointer
|
|
18
|
-
*
|
|
26
|
+
* @param list - The list or set to check
|
|
27
|
+
* @param pointer - The profile pointer to check
|
|
28
|
+
* @param type - Which types of tags to check
|
|
19
29
|
*/
|
|
20
|
-
export declare function isProfilePointerInList(list: NostrEvent, pointer: string | ProfilePointer): boolean;
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export declare function
|
|
30
|
+
export declare function isProfilePointerInList(list: NostrEvent, pointer: string | ProfilePointer, type?: ReadListTags): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Returns all the EventPointer in a list or set
|
|
33
|
+
* @param list - The list or set to get the event pointers from
|
|
34
|
+
* @param type - Which types of tags to read
|
|
35
|
+
*/
|
|
36
|
+
export declare function getEventPointersFromList(list: NostrEvent, type?: ReadListTags): EventPointer[];
|
|
37
|
+
/**
|
|
38
|
+
* Returns all the AddressPointer in a list or set
|
|
39
|
+
* @param list - The list or set to get the address pointers from
|
|
40
|
+
* @param type - Which types of tags to read
|
|
41
|
+
*/
|
|
42
|
+
export declare function getAddressPointersFromList(list: NostrEvent, type?: ReadListTags): AddressPointer[];
|
|
43
|
+
/**
|
|
44
|
+
* Returns all the ProfilePointer in a list or set
|
|
45
|
+
* @param list - The list or set to get the profile pointers from
|
|
46
|
+
* @param type - Which types of tags to read
|
|
47
|
+
*/
|
|
48
|
+
export declare function getProfilePointersFromList(list: NostrEvent, type?: ReadListTags): ProfilePointer[];
|
|
49
|
+
/**
|
|
50
|
+
* Returns a deduplicated array of all 'relay' tags in a list or set
|
|
51
|
+
* @param list - The list or set to get the relays from
|
|
52
|
+
* @param type - Which types of tags to read
|
|
53
|
+
*/
|
|
54
|
+
export declare function getRelaysFromList(list: NostrEvent, type?: ReadListTags): string[];
|
|
27
55
|
/** Returns if an event is a valid list or set */
|
|
28
56
|
export declare function isValidList(event: NostrEvent): boolean;
|
package/dist/helpers/lists.js
CHANGED
|
@@ -1,55 +1,94 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isAddressableKind, isReplaceableKind } from "nostr-tools/kinds";
|
|
2
2
|
import { getHiddenTags } from "./hidden-tags.js";
|
|
3
3
|
import { getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag, getProfilePointerFromPTag, } from "./pointers.js";
|
|
4
4
|
import { isATag, isETag, isPTag, processTags } from "./tags.js";
|
|
5
5
|
import { getReplaceableIdentifier } from "./event.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { mergeRelaySets } from "./relays.js";
|
|
7
|
+
export const FAVORITE_RELAYS_KIND = 10012;
|
|
8
|
+
/** Returns all the tags of a list or set */
|
|
9
|
+
export function getListTags(list, type) {
|
|
10
|
+
switch (type) {
|
|
11
|
+
case "public":
|
|
12
|
+
return list.tags;
|
|
13
|
+
case "hidden":
|
|
14
|
+
return getHiddenTags(list) ?? [];
|
|
15
|
+
default:
|
|
16
|
+
case "all":
|
|
17
|
+
return [...(getHiddenTags(list) ?? []), ...list.tags];
|
|
18
|
+
}
|
|
9
19
|
}
|
|
10
20
|
/**
|
|
11
21
|
* Checks if an event pointer is anywhere in a list or set
|
|
12
22
|
* NOTE: Ignores the `relay` field in EventPointer
|
|
13
|
-
*
|
|
23
|
+
* @param list - The list or set to check
|
|
24
|
+
* @param pointer - The event pointer to check
|
|
25
|
+
* @param type - Which types of tags to check
|
|
14
26
|
*/
|
|
15
|
-
export function isEventPointerInList(list, pointer) {
|
|
27
|
+
export function isEventPointerInList(list, pointer, type) {
|
|
16
28
|
const id = typeof pointer === "string" ? pointer : pointer.id;
|
|
17
|
-
|
|
29
|
+
const tags = getListTags(list, type);
|
|
30
|
+
return tags.some((t) => t[0] === "e" && t[1] === id);
|
|
18
31
|
}
|
|
19
32
|
/**
|
|
20
33
|
* Checks if an address pointer is anywhere in a list or set
|
|
21
34
|
* NOTE: Ignores the `relay` field in AddressPointer
|
|
22
|
-
*
|
|
35
|
+
* @param list - The list or set to check
|
|
36
|
+
* @param pointer - The address pointer to check
|
|
37
|
+
* @param type - Which types of tags to check
|
|
23
38
|
*/
|
|
24
|
-
export function isAddressPointerInList(list, pointer) {
|
|
39
|
+
export function isAddressPointerInList(list, pointer, type) {
|
|
25
40
|
const cord = typeof pointer === "string" ? pointer : getCoordinateFromAddressPointer(pointer);
|
|
26
|
-
|
|
41
|
+
const tags = getListTags(list, type);
|
|
42
|
+
return tags.some((t) => t[0] === "a" && t[1] === cord);
|
|
27
43
|
}
|
|
28
44
|
/**
|
|
29
45
|
* Checks if an profile pointer is anywhere in a list or set
|
|
30
46
|
* NOTE: Ignores the `relay` field in ProfilePointer
|
|
31
|
-
*
|
|
47
|
+
* @param list - The list or set to check
|
|
48
|
+
* @param pointer - The profile pointer to check
|
|
49
|
+
* @param type - Which types of tags to check
|
|
32
50
|
*/
|
|
33
|
-
export function isProfilePointerInList(list, pointer) {
|
|
51
|
+
export function isProfilePointerInList(list, pointer, type) {
|
|
34
52
|
const pubkey = typeof pointer === "string" ? pointer : pointer.pubkey;
|
|
35
|
-
|
|
53
|
+
const tags = getListTags(list, type);
|
|
54
|
+
return tags.some((t) => t[0] === "p" && t[1] === pubkey);
|
|
36
55
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Returns all the EventPointer in a list or set
|
|
58
|
+
* @param list - The list or set to get the event pointers from
|
|
59
|
+
* @param type - Which types of tags to read
|
|
60
|
+
*/
|
|
61
|
+
export function getEventPointersFromList(list, type) {
|
|
62
|
+
return processTags(getListTags(list, type), (tag) => (isETag(tag) ? tag : undefined), getEventPointerFromETag);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns all the AddressPointer in a list or set
|
|
66
|
+
* @param list - The list or set to get the address pointers from
|
|
67
|
+
* @param type - Which types of tags to read
|
|
68
|
+
*/
|
|
69
|
+
export function getAddressPointersFromList(list, type) {
|
|
70
|
+
return processTags(getListTags(list, type), (t) => (isATag(t) ? t : undefined), getAddressPointerFromATag);
|
|
40
71
|
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Returns all the ProfilePointer in a list or set
|
|
74
|
+
* @param list - The list or set to get the profile pointers from
|
|
75
|
+
* @param type - Which types of tags to read
|
|
76
|
+
*/
|
|
77
|
+
export function getProfilePointersFromList(list, type) {
|
|
78
|
+
return processTags(getListTags(list, type), (t) => (isPTag(t) ? t : undefined), getProfilePointerFromPTag);
|
|
44
79
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Returns a deduplicated array of all 'relay' tags in a list or set
|
|
82
|
+
* @param list - The list or set to get the relays from
|
|
83
|
+
* @param type - Which types of tags to read
|
|
84
|
+
*/
|
|
85
|
+
export function getRelaysFromList(list, type) {
|
|
86
|
+
return mergeRelaySets(processTags(getListTags(list, type), (t) => (t[0] === "relay" ? t[1] : undefined)));
|
|
48
87
|
}
|
|
49
88
|
/** Returns if an event is a valid list or set */
|
|
50
89
|
export function isValidList(event) {
|
|
51
90
|
try {
|
|
52
|
-
if (
|
|
91
|
+
if (isAddressableKind(event.kind)) {
|
|
53
92
|
// event is a set
|
|
54
93
|
// ensure the set has an identifier
|
|
55
94
|
getReplaceableIdentifier(event);
|
package/dist/helpers/mutes.d.ts
CHANGED
|
@@ -7,9 +7,17 @@ export type Mutes = {
|
|
|
7
7
|
hashtags: Set<string>;
|
|
8
8
|
words: Set<string>;
|
|
9
9
|
};
|
|
10
|
+
/** Merges any number of mute sets */
|
|
11
|
+
export declare function mergeMutes(...mutes: Mutes[]): Mutes;
|
|
10
12
|
/** Parses mute tags */
|
|
11
13
|
export declare function parseMutedTags(tags: string[][]): Mutes;
|
|
12
14
|
/** Returns muted things */
|
|
13
15
|
export declare function getMutedThings(mute: NostrEvent): Mutes;
|
|
16
|
+
/** Returns only the public muted things from a mute event */
|
|
17
|
+
export declare function getPublicMutedThings(mute: NostrEvent): Mutes;
|
|
14
18
|
/** Returns the hidden muted content if the event is unlocked */
|
|
15
19
|
export declare function getHiddenMutedThings(mute: NostrEvent): Mutes | undefined;
|
|
20
|
+
/** Creates a RegExp for matching muted words */
|
|
21
|
+
export declare function createMutedWordsRegExp(mutedWords: string[]): RegExp;
|
|
22
|
+
/** Returns true if the event matches the mutes */
|
|
23
|
+
export declare function matchMutes(mutes: Mutes, event: NostrEvent): boolean;
|
package/dist/helpers/mutes.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
import { kinds } from "nostr-tools";
|
|
1
2
|
import { isETag, isPTag, isTTag } from "./tags.js";
|
|
2
3
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
|
-
import { getHiddenTags } from "./hidden-tags.js";
|
|
4
|
+
import { getHiddenTags, isHiddenTagsLocked } from "./hidden-tags.js";
|
|
5
|
+
import { getIndexableTags, getNip10References } from "./index.js";
|
|
4
6
|
export const MutePublicSymbol = Symbol.for("mute-public");
|
|
5
7
|
export const MuteHiddenSymbol = Symbol.for("mute-hidden");
|
|
8
|
+
/** Merges any number of mute sets */
|
|
9
|
+
export function mergeMutes(...mutes) {
|
|
10
|
+
const mute = { pubkeys: new Set(), threads: new Set(), hashtags: new Set(), words: new Set() };
|
|
11
|
+
for (const m of mutes) {
|
|
12
|
+
for (const pubkey of m.pubkeys)
|
|
13
|
+
mute.pubkeys.add(pubkey);
|
|
14
|
+
for (const thread of m.threads)
|
|
15
|
+
mute.threads.add(thread);
|
|
16
|
+
for (const hashtag of m.hashtags)
|
|
17
|
+
mute.hashtags.add(hashtag);
|
|
18
|
+
for (const word of m.words)
|
|
19
|
+
mute.words.add(word);
|
|
20
|
+
}
|
|
21
|
+
return mute;
|
|
22
|
+
}
|
|
6
23
|
/** Parses mute tags */
|
|
7
24
|
export function parseMutedTags(tags) {
|
|
8
25
|
const pubkeys = new Set(tags.filter(isPTag).map((t) => t[1]));
|
|
@@ -13,12 +30,56 @@ export function parseMutedTags(tags) {
|
|
|
13
30
|
}
|
|
14
31
|
/** Returns muted things */
|
|
15
32
|
export function getMutedThings(mute) {
|
|
33
|
+
const hidden = getHiddenMutedThings(mute);
|
|
34
|
+
const mutes = getPublicMutedThings(mute);
|
|
35
|
+
if (hidden)
|
|
36
|
+
return mergeMutes(hidden, mutes);
|
|
37
|
+
return mutes;
|
|
38
|
+
}
|
|
39
|
+
/** Returns only the public muted things from a mute event */
|
|
40
|
+
export function getPublicMutedThings(mute) {
|
|
16
41
|
return getOrComputeCachedValue(mute, MutePublicSymbol, () => parseMutedTags(mute.tags));
|
|
17
42
|
}
|
|
18
43
|
/** Returns the hidden muted content if the event is unlocked */
|
|
19
44
|
export function getHiddenMutedThings(mute) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
45
|
+
if (isHiddenTagsLocked(mute))
|
|
46
|
+
return undefined;
|
|
47
|
+
return getOrComputeCachedValue(mute, MuteHiddenSymbol, () => parseMutedTags(getHiddenTags(mute)));
|
|
48
|
+
}
|
|
49
|
+
/** Creates a RegExp for matching muted words */
|
|
50
|
+
export function createMutedWordsRegExp(mutedWords) {
|
|
51
|
+
// Escape special characters and join with |
|
|
52
|
+
const escapedWords = mutedWords.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
53
|
+
// Create the RegExp with word boundaries and case insensitive flag
|
|
54
|
+
return new RegExp(`\\b(${escapedWords.join("|")})\\b`, "gi");
|
|
55
|
+
}
|
|
56
|
+
/** Returns true if the event matches the mutes */
|
|
57
|
+
export function matchMutes(mutes, event) {
|
|
58
|
+
// Filter on muted pubkeys
|
|
59
|
+
if (mutes.pubkeys.size > 0) {
|
|
60
|
+
if (mutes.pubkeys.has(event.pubkey))
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// Filter on muted hashtags`
|
|
64
|
+
if (mutes.hashtags.size > 0) {
|
|
65
|
+
const tags = getIndexableTags(event);
|
|
66
|
+
for (let tag of mutes.hashtags) {
|
|
67
|
+
if (tags.has("t:" + tag))
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Filter on muted threads
|
|
72
|
+
if (mutes.threads.size > 0 && event.kind === kinds.ShortTextNote) {
|
|
73
|
+
const refs = getNip10References(event);
|
|
74
|
+
if (refs.root?.e && mutes.threads.has(refs.root.e.id))
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
// Filter on muted words
|
|
78
|
+
if (mutes.words.size > 0) {
|
|
79
|
+
const regExp = createMutedWordsRegExp(Array.from(mutes.words));
|
|
80
|
+
if (regExp.test(event.content))
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
// Event does not match any mutes
|
|
84
|
+
return false;
|
|
24
85
|
}
|
package/dist/helpers/nip-19.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
import { AddressPointer, EventPointer, ProfilePointer } from "nostr-tools/nip19";
|
|
1
2
|
/** Gets the hex pubkey from any nip-19 encoded string */
|
|
2
3
|
export declare function normalizeToPubkey(str: string): string;
|
|
3
4
|
/** Converts hex to nsec strings into Uint8 secret keys */
|
|
4
5
|
export declare function normalizeToSecretKey(str: string): Uint8Array;
|
|
6
|
+
/**
|
|
7
|
+
* Merges two event points and keeps all relays
|
|
8
|
+
* @throws if the ids are different
|
|
9
|
+
*/
|
|
10
|
+
export declare function mergeEventPointers(a: EventPointer, b: EventPointer): EventPointer;
|
|
11
|
+
/** Merges two address pointers and keeps all relays
|
|
12
|
+
* @throws if the kinds, pubkeys, or identifiers are different
|
|
13
|
+
*/
|
|
14
|
+
export declare function mergeAddressPointers(a: AddressPointer, b: AddressPointer): AddressPointer;
|
|
15
|
+
/** Merges two profile pointers and keeps all relays
|
|
16
|
+
* @throws if the pubkeys are different
|
|
17
|
+
*/
|
|
18
|
+
export declare function mergeProfilePointers(a: ProfilePointer, b: ProfilePointer): ProfilePointer;
|
package/dist/helpers/nip-19.js
CHANGED
|
@@ -2,6 +2,7 @@ import { nip19 } from "nostr-tools";
|
|
|
2
2
|
import { hexToBytes } from "@noble/hashes/utils";
|
|
3
3
|
import { isHexKey } from "./string.js";
|
|
4
4
|
import { getPubkeyFromDecodeResult } from "./pointers.js";
|
|
5
|
+
import { mergeRelaySets } from "./relays.js";
|
|
5
6
|
/** Gets the hex pubkey from any nip-19 encoded string */
|
|
6
7
|
export function normalizeToPubkey(str) {
|
|
7
8
|
if (isHexKey(str))
|
|
@@ -25,3 +26,31 @@ export function normalizeToSecretKey(str) {
|
|
|
25
26
|
return decode.data;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Merges two event points and keeps all relays
|
|
31
|
+
* @throws if the ids are different
|
|
32
|
+
*/
|
|
33
|
+
export function mergeEventPointers(a, b) {
|
|
34
|
+
if (a.id !== b.id)
|
|
35
|
+
throw new Error("Cant merge event pointers with different ids");
|
|
36
|
+
const relays = mergeRelaySets(a.relays, b.relays);
|
|
37
|
+
return { id: a.id, kind: a.kind ?? b.kind, author: a.author ?? b.author, relays };
|
|
38
|
+
}
|
|
39
|
+
/** Merges two address pointers and keeps all relays
|
|
40
|
+
* @throws if the kinds, pubkeys, or identifiers are different
|
|
41
|
+
*/
|
|
42
|
+
export function mergeAddressPointers(a, b) {
|
|
43
|
+
if (a.kind !== b.kind || a.pubkey !== b.pubkey || a.identifier !== b.identifier)
|
|
44
|
+
throw new Error("Cant merge address pointers with different kinds, pubkeys, or identifiers");
|
|
45
|
+
const relays = mergeRelaySets(a.relays, b.relays);
|
|
46
|
+
return { ...a, relays };
|
|
47
|
+
}
|
|
48
|
+
/** Merges two profile pointers and keeps all relays
|
|
49
|
+
* @throws if the pubkeys are different
|
|
50
|
+
*/
|
|
51
|
+
export function mergeProfilePointers(a, b) {
|
|
52
|
+
if (a.pubkey !== b.pubkey)
|
|
53
|
+
throw new Error("Cant merge profile pointers with different pubkeys");
|
|
54
|
+
const relays = mergeRelaySets(a.relays, b.relays);
|
|
55
|
+
return { ...a, relays };
|
|
56
|
+
}
|