applesauce-core 0.12.1 → 1.2.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/__tests__/exports.test.d.ts +1 -0
- package/dist/__tests__/exports.test.js +17 -0
- 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__/exports.test.d.ts +1 -0
- package/dist/helpers/__tests__/exports.test.js +220 -0
- package/dist/helpers/__tests__/mutes.test.d.ts +1 -0
- package/dist/helpers/__tests__/mutes.test.js +55 -0
- package/dist/helpers/blossom.d.ts +2 -0
- package/dist/helpers/blossom.js +18 -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/helpers/profile.js +1 -1
- package/dist/observable/__tests__/exports.test.d.ts +1 -0
- package/dist/observable/__tests__/exports.test.js +18 -0
- 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 +5 -1
- package/dist/observable/index.js +6 -1
- package/dist/observable/listen-latest-updates.d.ts +5 -0
- package/dist/observable/listen-latest-updates.js +12 -0
- package/dist/promise/__tests__/exports.test.d.ts +1 -0
- package/dist/promise/__tests__/exports.test.js +11 -0
- package/dist/queries/__tests__/exports.test.d.ts +1 -0
- package/dist/queries/__tests__/exports.test.js +41 -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/__tests__/exports.test.d.ts +1 -0
- package/dist/query-store/__tests__/exports.test.js +12 -0
- 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
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as exports from "../index.js";
|
|
3
|
+
describe("exports", () => {
|
|
4
|
+
it("should export the expected functions", () => {
|
|
5
|
+
expect(Object.keys(exports).sort()).toMatchInlineSnapshot(`
|
|
6
|
+
[
|
|
7
|
+
"AUDIO_EXT",
|
|
8
|
+
"BLOSSOM_SERVER_LIST_KIND",
|
|
9
|
+
"BookmarkHiddenSymbol",
|
|
10
|
+
"BookmarkPublicSymbol",
|
|
11
|
+
"COMMENT_KIND",
|
|
12
|
+
"ChannelMetadataSymbol",
|
|
13
|
+
"CommentReplyPointerSymbol",
|
|
14
|
+
"CommentRootPointerSymbol",
|
|
15
|
+
"ContactsRelaysSymbol",
|
|
16
|
+
"EventContentEncryptionMethod",
|
|
17
|
+
"EventIndexableTagsSymbol",
|
|
18
|
+
"EventUIDSymbol",
|
|
19
|
+
"FAVORITE_RELAYS_KIND",
|
|
20
|
+
"FromCacheSymbol",
|
|
21
|
+
"GROUPS_LIST_KIND",
|
|
22
|
+
"GROUP_MESSAGE_KIND",
|
|
23
|
+
"GiftWrapEventSymbol",
|
|
24
|
+
"GiftWrapSealSymbol",
|
|
25
|
+
"GroupsHiddenSymbol",
|
|
26
|
+
"GroupsPublicSymbol",
|
|
27
|
+
"HiddenContactsSymbol",
|
|
28
|
+
"HiddenContentSymbol",
|
|
29
|
+
"HiddenTagsSymbol",
|
|
30
|
+
"IMAGE_EXT",
|
|
31
|
+
"LRU",
|
|
32
|
+
"MailboxesInboxesSymbol",
|
|
33
|
+
"MailboxesOutboxesSymbol",
|
|
34
|
+
"MediaAttachmentsSymbol",
|
|
35
|
+
"MuteHiddenSymbol",
|
|
36
|
+
"MutePublicSymbol",
|
|
37
|
+
"NIP05_REGEX",
|
|
38
|
+
"Nip10ThreadRefsSymbol",
|
|
39
|
+
"PICTURE_POST_KIND",
|
|
40
|
+
"ProfileContentSymbol",
|
|
41
|
+
"PublicContactsSymbol",
|
|
42
|
+
"ReplaceableIdentifierSymbol",
|
|
43
|
+
"STREAM_EXT",
|
|
44
|
+
"SeenRelaysSymbol",
|
|
45
|
+
"SharedEventSymbol",
|
|
46
|
+
"UserStatusPointerSymbol",
|
|
47
|
+
"VIDEO_EXT",
|
|
48
|
+
"ZapAddressPointerSymbol",
|
|
49
|
+
"ZapEventPointerSymbol",
|
|
50
|
+
"ZapFromSymbol",
|
|
51
|
+
"ZapInvoiceSymbol",
|
|
52
|
+
"ZapRequestSymbol",
|
|
53
|
+
"addSeenRelay",
|
|
54
|
+
"areBlossomServersEqual",
|
|
55
|
+
"canHaveHiddenContent",
|
|
56
|
+
"canHaveHiddenTags",
|
|
57
|
+
"convertToUrl",
|
|
58
|
+
"createMutedWordsRegExp",
|
|
59
|
+
"createReplaceableAddress",
|
|
60
|
+
"decodeGroupPointer",
|
|
61
|
+
"decodeLNURL",
|
|
62
|
+
"decryptDirectMessage",
|
|
63
|
+
"encodeDecodeResult",
|
|
64
|
+
"encodeGroupPointer",
|
|
65
|
+
"fakeVerifyEvent",
|
|
66
|
+
"getAddressPointerForEvent",
|
|
67
|
+
"getAddressPointerFromATag",
|
|
68
|
+
"getAddressPointersFromList",
|
|
69
|
+
"getBlossomServersFromList",
|
|
70
|
+
"getBookmarks",
|
|
71
|
+
"getCachedValue",
|
|
72
|
+
"getChannelMetadataContent",
|
|
73
|
+
"getChannelPointer",
|
|
74
|
+
"getCommentAddressPointer",
|
|
75
|
+
"getCommentEventPointer",
|
|
76
|
+
"getCommentExternalPointer",
|
|
77
|
+
"getCommentReplyPointer",
|
|
78
|
+
"getCommentRootPointer",
|
|
79
|
+
"getContacts",
|
|
80
|
+
"getContentWarning",
|
|
81
|
+
"getCoordinateFromAddressPointer",
|
|
82
|
+
"getDeleteCoordinates",
|
|
83
|
+
"getDeleteIds",
|
|
84
|
+
"getDisplayName",
|
|
85
|
+
"getEmojiTag",
|
|
86
|
+
"getEmojis",
|
|
87
|
+
"getEventPointerForEvent",
|
|
88
|
+
"getEventPointerFromETag",
|
|
89
|
+
"getEventPointerFromQTag",
|
|
90
|
+
"getEventPointerFromThreadTag",
|
|
91
|
+
"getEventPointersFromList",
|
|
92
|
+
"getEventUID",
|
|
93
|
+
"getExternalPointerFromTag",
|
|
94
|
+
"getFileMetadata",
|
|
95
|
+
"getFileMetadataFromImetaTag",
|
|
96
|
+
"getGiftWrapEvent",
|
|
97
|
+
"getGiftWrapSeal",
|
|
98
|
+
"getGroupPointerFromGroupTag",
|
|
99
|
+
"getHashtagTag",
|
|
100
|
+
"getHiddenBookmarks",
|
|
101
|
+
"getHiddenContacts",
|
|
102
|
+
"getHiddenContent",
|
|
103
|
+
"getHiddenContentEncryptionMethods",
|
|
104
|
+
"getHiddenGroups",
|
|
105
|
+
"getHiddenMutedThings",
|
|
106
|
+
"getHiddenTags",
|
|
107
|
+
"getHiddenTagsEncryptionMethods",
|
|
108
|
+
"getInboxes",
|
|
109
|
+
"getIndexableTags",
|
|
110
|
+
"getInvoice",
|
|
111
|
+
"getListTags",
|
|
112
|
+
"getMediaAttachments",
|
|
113
|
+
"getMutedThings",
|
|
114
|
+
"getNip10References",
|
|
115
|
+
"getOrComputeCachedValue",
|
|
116
|
+
"getOutboxes",
|
|
117
|
+
"getPackName",
|
|
118
|
+
"getParentEventStore",
|
|
119
|
+
"getPicturePostAttachments",
|
|
120
|
+
"getPointerForEvent",
|
|
121
|
+
"getPointerFromTag",
|
|
122
|
+
"getProfileContent",
|
|
123
|
+
"getProfilePointerFromPTag",
|
|
124
|
+
"getProfilePointersFromList",
|
|
125
|
+
"getPubkeyFromDecodeResult",
|
|
126
|
+
"getPublicBookmarks",
|
|
127
|
+
"getPublicContacts",
|
|
128
|
+
"getPublicGroups",
|
|
129
|
+
"getPublicMutedThings",
|
|
130
|
+
"getRelaysFromContactsEvent",
|
|
131
|
+
"getRelaysFromList",
|
|
132
|
+
"getReplaceableAddress",
|
|
133
|
+
"getReplaceableIdentifier",
|
|
134
|
+
"getReplaceableUID",
|
|
135
|
+
"getSeenRelays",
|
|
136
|
+
"getSha256FromURL",
|
|
137
|
+
"getTagValue",
|
|
138
|
+
"getURLFilename",
|
|
139
|
+
"getUserStatusPointer",
|
|
140
|
+
"getZapAddressPointer",
|
|
141
|
+
"getZapEventPointer",
|
|
142
|
+
"getZapPayment",
|
|
143
|
+
"getZapPreimage",
|
|
144
|
+
"getZapRecipient",
|
|
145
|
+
"getZapRequest",
|
|
146
|
+
"getZapSender",
|
|
147
|
+
"getZapSplits",
|
|
148
|
+
"hasHiddenContent",
|
|
149
|
+
"hasHiddenTags",
|
|
150
|
+
"interpretThreadTags",
|
|
151
|
+
"isATag",
|
|
152
|
+
"isAddressPointer",
|
|
153
|
+
"isAddressPointerInList",
|
|
154
|
+
"isAudioURL",
|
|
155
|
+
"isCommentAddressPointer",
|
|
156
|
+
"isCommentEventPointer",
|
|
157
|
+
"isDTag",
|
|
158
|
+
"isETag",
|
|
159
|
+
"isEvent",
|
|
160
|
+
"isEventPointer",
|
|
161
|
+
"isEventPointerInList",
|
|
162
|
+
"isFilterEqual",
|
|
163
|
+
"isFromCache",
|
|
164
|
+
"isGiftWrapLocked",
|
|
165
|
+
"isHex",
|
|
166
|
+
"isHexKey",
|
|
167
|
+
"isHiddenContentLocked",
|
|
168
|
+
"isHiddenTagsLocked",
|
|
169
|
+
"isImageURL",
|
|
170
|
+
"isNameValueTag",
|
|
171
|
+
"isNip05",
|
|
172
|
+
"isPTag",
|
|
173
|
+
"isProfilePointerInList",
|
|
174
|
+
"isRTag",
|
|
175
|
+
"isReplaceable",
|
|
176
|
+
"isSafeRelayURL",
|
|
177
|
+
"isSameURL",
|
|
178
|
+
"isSha256",
|
|
179
|
+
"isStreamURL",
|
|
180
|
+
"isTTag",
|
|
181
|
+
"isValidList",
|
|
182
|
+
"isValidProfile",
|
|
183
|
+
"isValidZap",
|
|
184
|
+
"isVideoURL",
|
|
185
|
+
"lockHiddenContent",
|
|
186
|
+
"lockHiddenTags",
|
|
187
|
+
"markFromCache",
|
|
188
|
+
"matchFilter",
|
|
189
|
+
"matchFilters",
|
|
190
|
+
"matchMutes",
|
|
191
|
+
"mergeBlossomServers",
|
|
192
|
+
"mergeBookmarks",
|
|
193
|
+
"mergeContacts",
|
|
194
|
+
"mergeFilters",
|
|
195
|
+
"mergeMutes",
|
|
196
|
+
"mergeRelaySets",
|
|
197
|
+
"normalizeURL",
|
|
198
|
+
"parseBolt11",
|
|
199
|
+
"parseBookmarkTags",
|
|
200
|
+
"parseCoordinate",
|
|
201
|
+
"parseExternalPointer",
|
|
202
|
+
"parseFileMetadataTags",
|
|
203
|
+
"parseLNURLOrAddress",
|
|
204
|
+
"parseLightningAddress",
|
|
205
|
+
"parseMutedTags",
|
|
206
|
+
"parseNIP05Address",
|
|
207
|
+
"parseSharedEvent",
|
|
208
|
+
"processTags",
|
|
209
|
+
"safeParse",
|
|
210
|
+
"setCachedValue",
|
|
211
|
+
"setEventContentEncryptionMethod",
|
|
212
|
+
"stripInvisibleChar",
|
|
213
|
+
"unixNow",
|
|
214
|
+
"unlockGiftWrap",
|
|
215
|
+
"unlockHiddenContent",
|
|
216
|
+
"unlockHiddenTags",
|
|
217
|
+
]
|
|
218
|
+
`);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { matchMutes } from "../mutes.js";
|
|
3
|
+
import { FakeUser } from "../../__tests__/fixtures.js";
|
|
4
|
+
const mutedUser = new FakeUser();
|
|
5
|
+
const nonMutedUser = new FakeUser();
|
|
6
|
+
const thread = nonMutedUser.note("Hello world");
|
|
7
|
+
// Create a mutes object with a pubkey to mute
|
|
8
|
+
const mutes = {
|
|
9
|
+
pubkeys: new Set([mutedUser.pubkey]),
|
|
10
|
+
threads: new Set([thread.id]),
|
|
11
|
+
hashtags: new Set(["nostr"]),
|
|
12
|
+
words: new Set(["GM"]),
|
|
13
|
+
};
|
|
14
|
+
describe("matchMutes", () => {
|
|
15
|
+
it("should match events with muted pubkeys", () => {
|
|
16
|
+
const mutedEvent = mutedUser.note("Hello world");
|
|
17
|
+
const nonMutedEvent = nonMutedUser.note("Hello world");
|
|
18
|
+
// The event with the muted pubkey should match
|
|
19
|
+
expect(matchMutes(mutes, mutedEvent)).toBe(true);
|
|
20
|
+
// The event with a different pubkey should not match
|
|
21
|
+
expect(matchMutes(mutes, nonMutedEvent)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
it("should match events with muted hashtags", () => {
|
|
24
|
+
// Create events with and without the muted hashtag
|
|
25
|
+
const eventWithMutedHashtag = nonMutedUser.note("Hello world");
|
|
26
|
+
eventWithMutedHashtag.tags.push(["t", "nostr"]);
|
|
27
|
+
const eventWithDifferentHashtag = nonMutedUser.note("Hello world");
|
|
28
|
+
eventWithDifferentHashtag.tags.push(["t", "bitcoin"]);
|
|
29
|
+
const eventWithNoHashtag = nonMutedUser.note("Hello world");
|
|
30
|
+
// The event with the muted hashtag should match
|
|
31
|
+
expect(matchMutes(mutes, eventWithMutedHashtag)).toBe(true);
|
|
32
|
+
// The events without the muted hashtag should not match
|
|
33
|
+
expect(matchMutes(mutes, eventWithDifferentHashtag)).toBe(false);
|
|
34
|
+
expect(matchMutes(mutes, eventWithNoHashtag)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it("should match events within threads", () => {
|
|
37
|
+
// Create a reply to the thread
|
|
38
|
+
const reply = nonMutedUser.note("Hello world");
|
|
39
|
+
reply.tags.push(["e", thread.id, "", "root"]);
|
|
40
|
+
// The reply should match the mute
|
|
41
|
+
expect(matchMutes(mutes, reply)).toBe(true);
|
|
42
|
+
// The thread should not match the mute
|
|
43
|
+
expect(matchMutes(mutes, thread)).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
it("should match events with muted words", () => {
|
|
46
|
+
// The event with the muted word should match
|
|
47
|
+
expect(matchMutes(mutes, nonMutedUser.note("GM"))).toBe(true);
|
|
48
|
+
// Should not match other words that contain the muted word
|
|
49
|
+
expect(matchMutes(mutes, nonMutedUser.note("GMing"))).toBe(false);
|
|
50
|
+
// Should be case-insensitive
|
|
51
|
+
expect(matchMutes(mutes, nonMutedUser.note("gm"))).toBe(true);
|
|
52
|
+
// Should match if the muted word
|
|
53
|
+
expect(matchMutes(mutes, nonMutedUser.note("Hello GM world"))).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -7,3 +7,5 @@ export declare function isSha256(str: string): boolean;
|
|
|
7
7
|
export declare function getBlossomServersFromList(event: {
|
|
8
8
|
tags: string[][];
|
|
9
9
|
} | string[][]): URL[];
|
|
10
|
+
/** A method that merges multiple arrays of blossom servers into a single array of unique servers */
|
|
11
|
+
export declare function mergeBlossomServers<T extends URL | string | (string | URL)>(...servers: (T | null | undefined | T[])[]): T[];
|
package/dist/helpers/blossom.js
CHANGED
|
@@ -20,3 +20,21 @@ export function getBlossomServersFromList(event) {
|
|
|
20
20
|
return undefined;
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
/** A method that merges multiple arrays of blossom servers into a single array of unique servers */
|
|
24
|
+
export function mergeBlossomServers(...servers) {
|
|
25
|
+
let merged = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
for (const arg of servers) {
|
|
28
|
+
let arr = Array.isArray(arg) ? arg : [arg];
|
|
29
|
+
for (const s of arr) {
|
|
30
|
+
if (s === null || s === undefined)
|
|
31
|
+
continue;
|
|
32
|
+
const key = new URL("/", s).toString();
|
|
33
|
+
if (seen.has(key))
|
|
34
|
+
continue;
|
|
35
|
+
seen.add(key);
|
|
36
|
+
merged.push(s);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return merged;
|
|
40
|
+
}
|
|
@@ -8,8 +8,13 @@ export type Bookmarks = {
|
|
|
8
8
|
hashtags: string[];
|
|
9
9
|
urls: string[];
|
|
10
10
|
};
|
|
11
|
+
/** Parses an array of tags into a {@link Bookmarks} object */
|
|
11
12
|
export declare function parseBookmarkTags(tags: string[][]): Bookmarks;
|
|
12
|
-
/**
|
|
13
|
+
/** Merges any number of {@link Bookmarks} objects */
|
|
14
|
+
export declare function mergeBookmarks(...bookmarks: (Bookmarks | undefined)[]): Bookmarks;
|
|
15
|
+
/** Returns all the bookmarks of the event */
|
|
13
16
|
export declare function getBookmarks(bookmark: NostrEvent): Bookmarks;
|
|
17
|
+
/** Returns the public bookmarks of the event */
|
|
18
|
+
export declare function getPublicBookmarks(bookmark: NostrEvent): Bookmarks;
|
|
14
19
|
/** Returns the bookmarks of the event if its unlocked */
|
|
15
20
|
export declare function getHiddenBookmarks(bookmark: NostrEvent): Bookmarks | undefined;
|
|
@@ -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)
|