applesauce-core 0.10.0 → 0.12.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/dist/__tests__/fixtures.d.ts +8 -0
- package/dist/__tests__/fixtures.js +20 -0
- package/dist/event-store/__tests__/event-store.test.js +272 -0
- package/dist/event-store/database.d.ts +7 -5
- package/dist/event-store/database.js +14 -8
- package/dist/event-store/event-store.d.ts +40 -20
- package/dist/event-store/event-store.js +269 -314
- package/dist/event-store/index.d.ts +1 -0
- package/dist/event-store/index.js +1 -0
- package/dist/event-store/interface.d.ts +27 -0
- package/dist/helpers/__tests__/blossom.test.js +13 -0
- package/dist/helpers/__tests__/comment.test.d.ts +1 -0
- package/dist/helpers/__tests__/comment.test.js +235 -0
- package/dist/helpers/__tests__/emoji.test.d.ts +1 -0
- package/dist/helpers/__tests__/emoji.test.js +15 -0
- package/dist/helpers/__tests__/event.test.d.ts +1 -0
- package/dist/helpers/__tests__/event.test.js +36 -0
- package/dist/helpers/__tests__/file-metadata.test.d.ts +1 -0
- package/dist/helpers/__tests__/file-metadata.test.js +103 -0
- package/dist/helpers/__tests__/hidden-tags.test.d.ts +1 -0
- package/dist/helpers/{hidden-tags.test.js → __tests__/hidden-tags.test.js} +2 -1
- package/dist/helpers/__tests__/mailboxes.test.d.ts +1 -0
- package/dist/helpers/{mailboxes.test.js → __tests__/mailboxes.test.js} +1 -1
- package/dist/helpers/__tests__/nip-19.test.d.ts +1 -0
- package/dist/helpers/__tests__/nip-19.test.js +42 -0
- package/dist/helpers/__tests__/relays.test.d.ts +1 -0
- package/dist/helpers/__tests__/relays.test.js +21 -0
- package/dist/helpers/__tests__/tags.test.d.ts +1 -0
- package/dist/helpers/__tests__/tags.test.js +24 -0
- package/dist/helpers/__tests__/threading.test.d.ts +1 -0
- package/dist/helpers/{threading.test.js → __tests__/threading.test.js} +1 -1
- package/dist/helpers/blossom.d.ts +9 -0
- package/dist/helpers/blossom.js +22 -0
- package/dist/helpers/bookmarks.d.ts +15 -0
- package/dist/helpers/bookmarks.js +27 -0
- package/dist/helpers/cache.d.ts +3 -4
- package/dist/helpers/cache.js +1 -1
- package/dist/helpers/channels.d.ts +10 -0
- package/dist/helpers/channels.js +27 -0
- package/dist/helpers/comment.d.ts +3 -4
- package/dist/helpers/comment.js +20 -16
- package/dist/helpers/contacts.d.ts +3 -0
- package/dist/helpers/contacts.js +25 -0
- package/dist/helpers/direct-messages.d.ts +4 -0
- package/dist/helpers/direct-messages.js +5 -0
- package/dist/helpers/dns-identity.d.ts +7 -0
- package/dist/helpers/dns-identity.js +10 -0
- package/dist/helpers/emoji.d.ts +3 -1
- package/dist/helpers/emoji.js +2 -2
- package/dist/helpers/event.d.ts +15 -1
- package/dist/helpers/event.js +34 -11
- package/dist/helpers/file-metadata.d.ts +55 -0
- package/dist/helpers/file-metadata.js +99 -0
- package/dist/helpers/filter.d.ts +4 -0
- package/dist/helpers/filter.js +34 -1
- package/dist/helpers/gift-wraps.d.ts +12 -0
- package/dist/helpers/gift-wraps.js +49 -0
- package/dist/helpers/groups.d.ts +24 -0
- package/dist/helpers/groups.js +39 -0
- package/dist/helpers/hidden-content.d.ts +48 -0
- package/dist/helpers/hidden-content.js +88 -0
- package/dist/helpers/hidden-tags.d.ts +17 -35
- package/dist/helpers/hidden-tags.js +26 -83
- package/dist/helpers/index.d.ts +16 -1
- package/dist/helpers/index.js +16 -1
- package/dist/helpers/lists.d.ts +28 -0
- package/dist/helpers/lists.js +65 -0
- package/dist/helpers/mailboxes.js +16 -9
- package/dist/helpers/mutes.d.ts +15 -0
- package/dist/helpers/mutes.js +24 -0
- package/dist/helpers/nip-19.d.ts +4 -0
- package/dist/helpers/nip-19.js +27 -0
- package/dist/helpers/picture-post.d.ts +4 -0
- package/dist/helpers/picture-post.js +6 -0
- package/dist/helpers/pointers.js +13 -17
- package/dist/helpers/profile.d.ts +6 -1
- package/dist/helpers/profile.js +4 -0
- package/dist/helpers/relays.d.ts +6 -3
- package/dist/helpers/relays.js +25 -18
- package/dist/helpers/share.d.ts +4 -0
- package/dist/helpers/share.js +12 -0
- package/dist/helpers/tags.d.ts +17 -0
- package/dist/helpers/tags.js +28 -6
- package/dist/helpers/threading.js +3 -3
- package/dist/helpers/url.d.ts +7 -0
- package/dist/helpers/url.js +27 -0
- package/dist/helpers/user-status.d.ts +18 -0
- package/dist/helpers/user-status.js +21 -0
- package/dist/observable/__tests__/claim-events.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-events.test.js +23 -0
- package/dist/observable/__tests__/claim-latest.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-latest.test.js +37 -0
- package/dist/observable/__tests__/simple-timeout.test.d.ts +1 -0
- package/dist/observable/__tests__/simple-timeout.test.js +34 -0
- package/dist/observable/claim-events.d.ts +5 -0
- package/dist/observable/claim-events.js +28 -0
- package/dist/observable/claim-latest.d.ts +5 -0
- package/dist/observable/claim-latest.js +21 -0
- package/dist/observable/{get-value.d.ts → get-observable-value.d.ts} +1 -1
- package/dist/observable/{get-value.js → get-observable-value.js} +3 -8
- package/dist/observable/index.d.ts +2 -1
- package/dist/observable/index.js +2 -1
- package/dist/observable/share-latest-value.d.ts +2 -4
- package/dist/observable/share-latest-value.js +19 -16
- package/dist/observable/simple-timeout.d.ts +4 -0
- package/dist/observable/simple-timeout.js +6 -0
- package/dist/observable/with-immediate-value.d.ts +3 -0
- package/dist/observable/with-immediate-value.js +19 -0
- package/dist/queries/blossom.d.ts +2 -0
- package/dist/queries/blossom.js +10 -0
- package/dist/queries/bookmarks.d.ts +8 -0
- package/dist/queries/bookmarks.js +23 -0
- package/dist/queries/channels.d.ts +11 -0
- package/dist/queries/channels.js +73 -0
- package/dist/queries/contacts.d.ts +3 -0
- package/dist/queries/contacts.js +12 -0
- package/dist/queries/index.d.ts +6 -0
- package/dist/queries/index.js +6 -0
- package/dist/queries/mutes.d.ts +8 -0
- package/dist/queries/mutes.js +23 -0
- package/dist/queries/pins.d.ts +3 -0
- package/dist/queries/pins.js +12 -0
- package/dist/queries/simple.d.ts +3 -3
- package/dist/queries/simple.js +3 -3
- package/dist/queries/thread.js +1 -1
- package/dist/queries/user-status.d.ts +11 -0
- package/dist/queries/user-status.js +39 -0
- package/dist/query-store/__tests__/query-store.test.d.ts +1 -0
- package/dist/query-store/__tests__/query-store.test.js +63 -0
- package/dist/query-store/index.d.ts +1 -57
- package/dist/query-store/index.js +1 -66
- package/dist/query-store/query-store.d.ts +53 -0
- package/dist/query-store/query-store.js +97 -0
- package/package.json +20 -8
- package/dist/helpers/media-attachment.d.ts +0 -33
- package/dist/helpers/media-attachment.js +0 -60
- /package/dist/{helpers/hidden-tags.test.d.ts → event-store/__tests__/event-store.test.d.ts} +0 -0
- /package/dist/{helpers/mailboxes.test.d.ts → event-store/interface.js} +0 -0
- /package/dist/helpers/{threading.test.d.ts → __tests__/blossom.test.d.ts} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { kinds } from "nostr-tools";
|
|
2
|
+
import { getAddressPointerFromATag, getEventPointerFromETag } from "./pointers.js";
|
|
3
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
4
|
+
import { getHiddenTags } from "./index.js";
|
|
5
|
+
export const BookmarkPublicSymbol = Symbol.for("bookmark-public");
|
|
6
|
+
export const BookmarkHiddenSymbol = Symbol.for("bookmark-hidden");
|
|
7
|
+
export function parseBookmarkTags(tags) {
|
|
8
|
+
const notes = tags.filter((t) => t[0] === "e" && t[1]).map(getEventPointerFromETag);
|
|
9
|
+
const articles = tags
|
|
10
|
+
.filter((t) => t[0] === "a" && t[1])
|
|
11
|
+
.map(getAddressPointerFromATag)
|
|
12
|
+
.filter((addr) => addr.kind === kinds.LongFormArticle);
|
|
13
|
+
const hashtags = tags.filter((t) => t[0] === "t" && t[1]).map((t) => t[1]);
|
|
14
|
+
const urls = tags.filter((t) => t[0] === "r" && t[1]).map((t) => t[1]);
|
|
15
|
+
return { notes, articles, hashtags, urls };
|
|
16
|
+
}
|
|
17
|
+
/** Returns the public bookmarks of the event */
|
|
18
|
+
export function getBookmarks(bookmark) {
|
|
19
|
+
return getOrComputeCachedValue(bookmark, BookmarkPublicSymbol, () => parseBookmarkTags(bookmark.tags));
|
|
20
|
+
}
|
|
21
|
+
/** Returns the bookmarks of the event if its unlocked */
|
|
22
|
+
export function getHiddenBookmarks(bookmark) {
|
|
23
|
+
return getOrComputeCachedValue(bookmark, BookmarkHiddenSymbol, () => {
|
|
24
|
+
const tags = getHiddenTags(bookmark);
|
|
25
|
+
return tags && parseBookmarkTags(tags);
|
|
26
|
+
});
|
|
27
|
+
}
|
package/dist/helpers/cache.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function setCachedValue<T extends unknown>(event: NostrEvent | EventTemplate, symbol: symbol, value: T): void;
|
|
1
|
+
export declare function getCachedValue<T extends unknown>(event: any, symbol: symbol): T | undefined;
|
|
2
|
+
export declare function setCachedValue<T extends unknown>(event: any, symbol: symbol, value: T): void;
|
|
4
3
|
/** Internal method used to cache computed values on events */
|
|
5
|
-
export declare function getOrComputeCachedValue<T extends unknown>(event:
|
|
4
|
+
export declare function getOrComputeCachedValue<T extends unknown>(event: any, symbol: symbol, compute: () => T): T;
|
package/dist/helpers/cache.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { nip19, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { ChannelMetadata } from "nostr-tools/nip28";
|
|
3
|
+
export declare const ChannelMetadataSymbol: unique symbol;
|
|
4
|
+
export type ChannelMetadataContent = ChannelMetadata & {
|
|
5
|
+
relays?: string[];
|
|
6
|
+
};
|
|
7
|
+
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
8
|
+
export declare function getChannelMetadataContent(channel: NostrEvent): ChannelMetadataContent;
|
|
9
|
+
/** gets the EventPointer for a channel message or metadata event */
|
|
10
|
+
export declare function getChannelPointer(event: NostrEvent): nip19.EventPointer | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
export const ChannelMetadataSymbol = Symbol.for("channel-metadata");
|
|
3
|
+
function parseChannelMetadataContent(channel) {
|
|
4
|
+
const metadata = JSON.parse(channel.content);
|
|
5
|
+
if (metadata.name === undefined)
|
|
6
|
+
throw new Error("Missing name");
|
|
7
|
+
if (metadata.about === undefined)
|
|
8
|
+
throw new Error("Missing about");
|
|
9
|
+
if (metadata.picture === undefined)
|
|
10
|
+
throw new Error("Missing picture");
|
|
11
|
+
if (metadata.relays && !Array.isArray(metadata.relays))
|
|
12
|
+
throw new Error("Invalid relays");
|
|
13
|
+
return metadata;
|
|
14
|
+
}
|
|
15
|
+
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
16
|
+
export function getChannelMetadataContent(channel) {
|
|
17
|
+
return getOrComputeCachedValue(channel, ChannelMetadataSymbol, () => {
|
|
18
|
+
return parseChannelMetadataContent(channel);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** gets the EventPointer for a channel message or metadata event */
|
|
22
|
+
export function getChannelPointer(event) {
|
|
23
|
+
const tag = event.tags.find((t) => t[0] === "e" && t[1]);
|
|
24
|
+
if (!tag)
|
|
25
|
+
return undefined;
|
|
26
|
+
return tag[2] ? { id: tag[1], relays: [tag[2]] } : { id: tag[1] };
|
|
27
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { NostrEvent } from "nostr-tools";
|
|
2
2
|
import { ExternalPointer, ExternalIdentifiers } from "./external-id.js";
|
|
3
3
|
export declare const COMMENT_KIND = 1111;
|
|
4
|
-
type CommentEventPointer = {
|
|
4
|
+
export type CommentEventPointer = {
|
|
5
5
|
id: string;
|
|
6
6
|
kind: number;
|
|
7
7
|
pubkey?: string;
|
|
8
8
|
relay?: string;
|
|
9
9
|
};
|
|
10
|
-
type CommentAddressPointer = {
|
|
10
|
+
export type CommentAddressPointer = {
|
|
11
11
|
id?: string;
|
|
12
12
|
kind: number;
|
|
13
13
|
pubkey: string;
|
|
14
14
|
identifier: string;
|
|
15
15
|
relay?: string;
|
|
16
16
|
};
|
|
17
|
-
type CommentExternalPointer = ExternalPointer<keyof ExternalIdentifiers>;
|
|
17
|
+
export type CommentExternalPointer = ExternalPointer<keyof ExternalIdentifiers>;
|
|
18
18
|
export type CommentPointer = CommentEventPointer | CommentAddressPointer | CommentExternalPointer;
|
|
19
19
|
export declare const CommentRootPointerSymbol: unique symbol;
|
|
20
20
|
export declare const CommentReplyPointerSymbol: unique symbol;
|
|
@@ -45,4 +45,3 @@ export declare function getCommentRootPointer(comment: NostrEvent): CommentPoint
|
|
|
45
45
|
export declare function getCommentReplyPointer(comment: NostrEvent): CommentPointer | null;
|
|
46
46
|
export declare function isCommentEventPointer(pointer: any): pointer is CommentEventPointer;
|
|
47
47
|
export declare function isCommentAddressPointer(pointer: any): pointer is CommentAddressPointer;
|
|
48
|
-
export {};
|
package/dist/helpers/comment.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getExternalPointerFromTag } from "./external-id.js";
|
|
2
2
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
3
|
import { getAddressPointerFromATag } from "./pointers.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isSafeRelayURL } from "./relays.js";
|
|
5
5
|
export const COMMENT_KIND = 1111;
|
|
6
6
|
export const CommentRootPointerSymbol = Symbol.for("comment-root-pointer");
|
|
7
7
|
export const CommentReplyPointerSymbol = Symbol.for("comment-reply-pointer");
|
|
@@ -10,16 +10,18 @@ export const CommentReplyPointerSymbol = Symbol.for("comment-reply-pointer");
|
|
|
10
10
|
* @throws
|
|
11
11
|
*/
|
|
12
12
|
export function getCommentEventPointer(tags, root = false) {
|
|
13
|
-
const
|
|
13
|
+
const eTag = tags.find((t) => t[0] === (root ? "E" : "e"));
|
|
14
14
|
const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
|
|
15
|
-
if (
|
|
15
|
+
if (eTag) {
|
|
16
16
|
if (!kind)
|
|
17
17
|
throw new Error("Missing kind tag");
|
|
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
|
+
const rootPubkey = root ? tags.find((t) => t[0] === "P")?.[1] : undefined;
|
|
18
20
|
const pointer = {
|
|
19
|
-
id:
|
|
21
|
+
id: eTag[1],
|
|
20
22
|
kind: parseInt(kind),
|
|
21
|
-
pubkey:
|
|
22
|
-
relay:
|
|
23
|
+
pubkey: eTag[3] || rootPubkey || undefined,
|
|
24
|
+
relay: eTag[2] && isSafeRelayURL(eTag[2]) ? eTag[2] : undefined,
|
|
23
25
|
};
|
|
24
26
|
return pointer;
|
|
25
27
|
}
|
|
@@ -30,16 +32,19 @@ export function getCommentEventPointer(tags, root = false) {
|
|
|
30
32
|
* @throws
|
|
31
33
|
*/
|
|
32
34
|
export function getCommentAddressPointer(tags, root = false) {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
+
const aTag = tags.find((t) => t[0] === (root ? "A" : "a"));
|
|
36
|
+
const eTag = tags.find((t) => t[0] === (root ? "E" : "e"));
|
|
35
37
|
const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
|
|
36
|
-
if (
|
|
38
|
+
if (aTag) {
|
|
37
39
|
if (!kind)
|
|
38
40
|
throw new Error("Missing kind tag");
|
|
41
|
+
const addressPointer = getAddressPointerFromATag(aTag);
|
|
39
42
|
const pointer = {
|
|
40
|
-
id,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
id: eTag?.[1],
|
|
44
|
+
pubkey: addressPointer.pubkey,
|
|
45
|
+
identifier: addressPointer.identifier,
|
|
46
|
+
kind: addressPointer.kind || parseInt(kind),
|
|
47
|
+
relay: addressPointer.relays?.[0] || eTag?.[2],
|
|
43
48
|
};
|
|
44
49
|
return pointer;
|
|
45
50
|
}
|
|
@@ -50,13 +55,12 @@ export function getCommentAddressPointer(tags, root = false) {
|
|
|
50
55
|
* @throws
|
|
51
56
|
*/
|
|
52
57
|
export function getCommentExternalPointer(tags, root = false) {
|
|
53
|
-
const
|
|
58
|
+
const iTag = tags.find((t) => t[0] === (root ? "I" : "i"));
|
|
54
59
|
const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
|
|
55
|
-
if (
|
|
60
|
+
if (iTag) {
|
|
56
61
|
if (!kind)
|
|
57
62
|
throw new Error("Missing kind tag");
|
|
58
|
-
|
|
59
|
-
return pointer;
|
|
63
|
+
return getExternalPointerFromTag(iTag);
|
|
60
64
|
}
|
|
61
65
|
return null;
|
|
62
66
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
import { isSafeRelayURL } from "./relays.js";
|
|
3
|
+
export const ContactsRelaysSymbol = Symbol.for("contacts-relays");
|
|
4
|
+
export function getRelaysFromContactsEvent(event) {
|
|
5
|
+
return getOrComputeCachedValue(event, ContactsRelaysSymbol, () => {
|
|
6
|
+
try {
|
|
7
|
+
const relayJson = JSON.parse(event.content);
|
|
8
|
+
const relays = new Map();
|
|
9
|
+
for (const [url, opts] of Object.entries(relayJson)) {
|
|
10
|
+
if (!isSafeRelayURL(url))
|
|
11
|
+
continue;
|
|
12
|
+
if (opts.write && opts.read)
|
|
13
|
+
relays.set(url, "all");
|
|
14
|
+
else if (opts.read)
|
|
15
|
+
relays.set(url, "inbox");
|
|
16
|
+
else if (opts.write)
|
|
17
|
+
relays.set(url, "outbox");
|
|
18
|
+
}
|
|
19
|
+
return relays;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
import { HiddenContentSigner } from "./hidden-content.js";
|
|
3
|
+
/** Returns the decrypted content of a direct message */
|
|
4
|
+
export declare function decryptDirectMessage(message: NostrEvent, signer: HiddenContentSigner): Promise<string>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { getHiddenContent, unlockHiddenContent } from "./hidden-content.js";
|
|
2
|
+
/** Returns the decrypted content of a direct message */
|
|
3
|
+
export async function decryptDirectMessage(message, signer) {
|
|
4
|
+
return getHiddenContent(message) || (await unlockHiddenContent(message, signer));
|
|
5
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isNip05, NIP05_REGEX } from "nostr-tools/nip05";
|
|
2
|
+
/** Returns the name and domain for a NIP-05 address */
|
|
3
|
+
export function parseNIP05Address(address) {
|
|
4
|
+
const match = address.toLowerCase().match(NIP05_REGEX);
|
|
5
|
+
if (!match)
|
|
6
|
+
return null;
|
|
7
|
+
const [, name = "_", domain] = match;
|
|
8
|
+
return { name, domain };
|
|
9
|
+
}
|
|
10
|
+
export { isNip05, NIP05_REGEX };
|
package/dist/helpers/emoji.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export declare function getEmojiTag(event: NostrEvent | EventTemplate, code: str
|
|
|
4
4
|
/** Returns the name of a NIP-30 emoji pack */
|
|
5
5
|
export declare function getPackName(pack: NostrEvent): string | undefined;
|
|
6
6
|
export type Emoji = {
|
|
7
|
-
|
|
7
|
+
/** The emoji shortcode (without the ::) */
|
|
8
|
+
shortcode: string;
|
|
9
|
+
/** The URL to the emoji image */
|
|
8
10
|
url: string;
|
|
9
11
|
};
|
|
10
12
|
/** Returns an array of emojis from a NIP-30 emoji pack */
|
package/dist/helpers/emoji.js
CHANGED
|
@@ -2,7 +2,7 @@ import { getTagValue } from "./event.js";
|
|
|
2
2
|
/** Gets an "emoji" tag that matches an emoji code */
|
|
3
3
|
export function getEmojiTag(event, code) {
|
|
4
4
|
code = code.replace(/^:|:$/g, "").toLocaleLowerCase();
|
|
5
|
-
return event.tags.
|
|
5
|
+
return event.tags.find((t) => t[0] === "emoji" && t.length >= 3 && t[1].toLowerCase() === code);
|
|
6
6
|
}
|
|
7
7
|
/** Returns the name of a NIP-30 emoji pack */
|
|
8
8
|
export function getPackName(pack) {
|
|
@@ -12,5 +12,5 @@ export function getPackName(pack) {
|
|
|
12
12
|
export function getEmojis(pack) {
|
|
13
13
|
return pack.tags
|
|
14
14
|
.filter((t) => t[0] === "emoji" && t[1] && t[2])
|
|
15
|
-
.map((t) => ({
|
|
15
|
+
.map((t) => ({ shortcode: t[1], url: t[2] }));
|
|
16
16
|
}
|
package/dist/helpers/event.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NostrEvent, VerifiedEvent } from "nostr-tools";
|
|
2
|
+
import { IEventStore } from "../event-store/interface.js";
|
|
2
3
|
export declare const EventUIDSymbol: unique symbol;
|
|
3
4
|
export declare const EventIndexableTagsSymbol: unique symbol;
|
|
4
5
|
export declare const FromCacheSymbol: unique symbol;
|
|
6
|
+
export declare const ReplaceableIdentifierSymbol: unique symbol;
|
|
5
7
|
declare module "nostr-tools" {
|
|
6
8
|
interface Event {
|
|
7
9
|
[EventUIDSymbol]?: string;
|
|
@@ -33,10 +35,22 @@ export declare function getIndexableTags(event: NostrEvent): Set<string>;
|
|
|
33
35
|
* Returns the second index ( tag[1] ) of the first tag that matches the name
|
|
34
36
|
* If the event has any hidden tags they will be searched first
|
|
35
37
|
*/
|
|
36
|
-
export declare function getTagValue
|
|
38
|
+
export declare function getTagValue<T extends {
|
|
39
|
+
kind: number;
|
|
40
|
+
tags: string[][];
|
|
41
|
+
content: string;
|
|
42
|
+
pubkey: string;
|
|
43
|
+
}>(event: T, name: string): string | undefined;
|
|
37
44
|
/** Sets events verified flag without checking anything */
|
|
38
45
|
export declare function fakeVerifyEvent(event: NostrEvent): event is VerifiedEvent;
|
|
39
46
|
/** Marks an event as being from a cache */
|
|
40
47
|
export declare function markFromCache(event: NostrEvent): void;
|
|
41
48
|
/** Returns if an event was from a cache */
|
|
42
49
|
export declare function isFromCache(event: NostrEvent): boolean;
|
|
50
|
+
/** Returns the EventStore of an event if its been added to one */
|
|
51
|
+
export declare function getParentEventStore<T extends object>(event: T): IEventStore | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the replaceable identifier for a replaceable event
|
|
54
|
+
* @throws
|
|
55
|
+
*/
|
|
56
|
+
export declare function getReplaceableIdentifier(event: NostrEvent): string;
|
package/dist/helpers/event.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { kinds, verifiedSymbol } from "nostr-tools";
|
|
2
2
|
import { INDEXABLE_TAGS } from "../event-store/common.js";
|
|
3
3
|
import { getHiddenTags } from "./hidden-tags.js";
|
|
4
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
5
|
+
import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
|
|
6
|
+
import { EventStoreSymbol } from "../event-store/event-store.js";
|
|
4
7
|
export const EventUIDSymbol = Symbol.for("event-uid");
|
|
5
8
|
export const EventIndexableTagsSymbol = Symbol.for("indexable-tags");
|
|
6
9
|
export const FromCacheSymbol = Symbol.for("from-cache");
|
|
10
|
+
export const ReplaceableIdentifierSymbol = Symbol.for("replaceable-identifier");
|
|
7
11
|
/**
|
|
8
12
|
* Checks if an object is a nostr event
|
|
9
13
|
* NOTE: does not validation the signature on the event
|
|
@@ -34,20 +38,20 @@ export function isReplaceable(kind) {
|
|
|
34
38
|
* For parametrized replaceable events this is ( event.kind + ":" + event.pubkey + ":" + event.tags.d.1 )
|
|
35
39
|
*/
|
|
36
40
|
export function getEventUID(event) {
|
|
37
|
-
let
|
|
38
|
-
if (!
|
|
41
|
+
let uid = event[EventUIDSymbol];
|
|
42
|
+
if (!uid) {
|
|
39
43
|
if (isReplaceable(event.kind)) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
id = event.id;
|
|
44
|
+
let d = event.tags.find((t) => t[0] === "d")?.[1];
|
|
45
|
+
uid = getReplaceableUID(event.kind, event.pubkey, d);
|
|
45
46
|
}
|
|
47
|
+
else
|
|
48
|
+
uid = event.id;
|
|
49
|
+
event[EventUIDSymbol] = uid;
|
|
46
50
|
}
|
|
47
|
-
return
|
|
51
|
+
return uid;
|
|
48
52
|
}
|
|
49
53
|
export function getReplaceableUID(kind, pubkey, d) {
|
|
50
|
-
return d ?
|
|
54
|
+
return d ? kind + ":" + pubkey + ":" + d : kind + ":" + pubkey;
|
|
51
55
|
}
|
|
52
56
|
/** Returns a Set of tag names and values that are indexable */
|
|
53
57
|
export function getIndexableTags(event) {
|
|
@@ -55,7 +59,7 @@ export function getIndexableTags(event) {
|
|
|
55
59
|
if (!indexable) {
|
|
56
60
|
const tags = new Set();
|
|
57
61
|
for (const tag of event.tags) {
|
|
58
|
-
if (tag[0] && INDEXABLE_TAGS.has(tag[0])
|
|
62
|
+
if (tag.length >= 2 && tag[0].length === 1 && INDEXABLE_TAGS.has(tag[0])) {
|
|
59
63
|
tags.add(tag[0] + ":" + tag[1]);
|
|
60
64
|
}
|
|
61
65
|
}
|
|
@@ -76,7 +80,8 @@ export function getTagValue(event, name) {
|
|
|
76
80
|
}
|
|
77
81
|
/** Sets events verified flag without checking anything */
|
|
78
82
|
export function fakeVerifyEvent(event) {
|
|
79
|
-
|
|
83
|
+
event[verifiedSymbol] = true;
|
|
84
|
+
return true;
|
|
80
85
|
}
|
|
81
86
|
/** Marks an event as being from a cache */
|
|
82
87
|
export function markFromCache(event) {
|
|
@@ -86,3 +91,21 @@ export function markFromCache(event) {
|
|
|
86
91
|
export function isFromCache(event) {
|
|
87
92
|
return !!event[FromCacheSymbol];
|
|
88
93
|
}
|
|
94
|
+
/** Returns the EventStore of an event if its been added to one */
|
|
95
|
+
export function getParentEventStore(event) {
|
|
96
|
+
return Reflect.get(event, EventStoreSymbol);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns the replaceable identifier for a replaceable event
|
|
100
|
+
* @throws
|
|
101
|
+
*/
|
|
102
|
+
export function getReplaceableIdentifier(event) {
|
|
103
|
+
if (!isParameterizedReplaceableKind(event.kind))
|
|
104
|
+
throw new Error("Event is not replaceable");
|
|
105
|
+
return getOrComputeCachedValue(event, ReplaceableIdentifierSymbol, () => {
|
|
106
|
+
const d = getTagValue(event, "d");
|
|
107
|
+
if (d === undefined)
|
|
108
|
+
throw new Error("Event missing identifier");
|
|
109
|
+
return d;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
export type FileMetadata = {
|
|
3
|
+
/** URL of the file */
|
|
4
|
+
url: string;
|
|
5
|
+
/** MIME type */
|
|
6
|
+
type?: string;
|
|
7
|
+
/** sha256 hash of the file */
|
|
8
|
+
sha256?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The original sha256 hash before the file was transformed
|
|
11
|
+
* @deprecated
|
|
12
|
+
*/
|
|
13
|
+
originalSha256?: string;
|
|
14
|
+
/** size of the file in bytes */
|
|
15
|
+
size?: number;
|
|
16
|
+
/** size of file in pixels in the form <width>x<height> */
|
|
17
|
+
dimensions?: string;
|
|
18
|
+
/** magnet */
|
|
19
|
+
magnet?: string;
|
|
20
|
+
/** torrent infohash */
|
|
21
|
+
infohash?: string;
|
|
22
|
+
/** URL to a thumbnail */
|
|
23
|
+
thumbnail?: string;
|
|
24
|
+
/** URL to a preview image with the same dimensions */
|
|
25
|
+
image?: string;
|
|
26
|
+
/** summary */
|
|
27
|
+
summary?: string;
|
|
28
|
+
/** description for accessability */
|
|
29
|
+
alt?: string;
|
|
30
|
+
/** blurhash */
|
|
31
|
+
blurhash?: string;
|
|
32
|
+
/** fallback URLs */
|
|
33
|
+
fallback?: string[];
|
|
34
|
+
};
|
|
35
|
+
export type MediaAttachment = FileMetadata;
|
|
36
|
+
/**
|
|
37
|
+
* Parses file metadata tags into {@link FileMetadata}
|
|
38
|
+
* @throws
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseFileMetadataTags(tags: string[][]): FileMetadata;
|
|
41
|
+
/**
|
|
42
|
+
* Parses a imeta tag into a {@link FileMetadata}
|
|
43
|
+
* @throws
|
|
44
|
+
*/
|
|
45
|
+
export declare function getFileMetadataFromImetaTag(tag: string[]): FileMetadata;
|
|
46
|
+
export declare const MediaAttachmentsSymbol: unique symbol;
|
|
47
|
+
/** Gets all the media attachments on an event */
|
|
48
|
+
export declare function getMediaAttachments(event: NostrEvent): FileMetadata[];
|
|
49
|
+
/**
|
|
50
|
+
* Gets {@link FileMetadata} for a NIP-94 kind 1063 event
|
|
51
|
+
* @throws
|
|
52
|
+
*/
|
|
53
|
+
export declare function getFileMetadata(file: NostrEvent): FileMetadata;
|
|
54
|
+
/** Returns the last 64 length hex string in a URL */
|
|
55
|
+
export declare function getSha256FromURL(url: string | URL): string | undefined;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parses file metadata tags into {@link FileMetadata}
|
|
4
|
+
* @throws
|
|
5
|
+
*/
|
|
6
|
+
export function parseFileMetadataTags(tags) {
|
|
7
|
+
const fields = {};
|
|
8
|
+
let fallback = undefined;
|
|
9
|
+
for (const [name, value] of tags) {
|
|
10
|
+
switch (name) {
|
|
11
|
+
case "fallback":
|
|
12
|
+
fallback = fallback ? [...fallback, value] : [value];
|
|
13
|
+
break;
|
|
14
|
+
default:
|
|
15
|
+
fields[name] = value;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (!fields.url)
|
|
20
|
+
throw new Error("Missing required url in file metadata");
|
|
21
|
+
const metadata = { url: fields.url, fallback };
|
|
22
|
+
// parse size
|
|
23
|
+
if (fields.size)
|
|
24
|
+
metadata.size = parseInt(fields.size);
|
|
25
|
+
// copy optional fields
|
|
26
|
+
if (fields.m)
|
|
27
|
+
metadata.type = fields.m;
|
|
28
|
+
if (fields.x)
|
|
29
|
+
metadata.sha256 = fields.x;
|
|
30
|
+
if (fields.ox)
|
|
31
|
+
metadata.originalSha256 = fields.ox;
|
|
32
|
+
if (fields.dim)
|
|
33
|
+
metadata.dimensions = fields.dim;
|
|
34
|
+
if (fields.magnet)
|
|
35
|
+
metadata.magnet = fields.magnet;
|
|
36
|
+
if (fields.i)
|
|
37
|
+
metadata.infohash = fields.i;
|
|
38
|
+
if (fields.thumb)
|
|
39
|
+
metadata.thumbnail = fields.thumb;
|
|
40
|
+
if (fields.image)
|
|
41
|
+
metadata.image = fields.image;
|
|
42
|
+
if (fields.summary)
|
|
43
|
+
metadata.summary = fields.summary;
|
|
44
|
+
if (fields.alt)
|
|
45
|
+
metadata.alt = fields.alt;
|
|
46
|
+
if (fields.blurhash)
|
|
47
|
+
metadata.blurhash = fields.blurhash;
|
|
48
|
+
return metadata;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parses a imeta tag into a {@link FileMetadata}
|
|
52
|
+
* @throws
|
|
53
|
+
*/
|
|
54
|
+
export function getFileMetadataFromImetaTag(tag) {
|
|
55
|
+
const parts = tag.slice(1);
|
|
56
|
+
const tags = [];
|
|
57
|
+
for (const part of parts) {
|
|
58
|
+
const match = part.match(/^(.+?)\s(.+)$/);
|
|
59
|
+
if (match) {
|
|
60
|
+
const [_, name, value] = match;
|
|
61
|
+
tags.push([name, value]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return parseFileMetadataTags(tags);
|
|
65
|
+
}
|
|
66
|
+
export const MediaAttachmentsSymbol = Symbol.for("media-attachments");
|
|
67
|
+
/** Gets all the media attachments on an event */
|
|
68
|
+
export function getMediaAttachments(event) {
|
|
69
|
+
return getOrComputeCachedValue(event, MediaAttachmentsSymbol, () => {
|
|
70
|
+
return event.tags
|
|
71
|
+
.filter((t) => t[0] === "imeta")
|
|
72
|
+
.map((tag) => {
|
|
73
|
+
try {
|
|
74
|
+
return getFileMetadataFromImetaTag(tag);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// ignore invalid attachments
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
.filter((a) => !!a);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Gets {@link FileMetadata} for a NIP-94 kind 1063 event
|
|
86
|
+
* @throws
|
|
87
|
+
*/
|
|
88
|
+
export function getFileMetadata(file) {
|
|
89
|
+
return parseFileMetadataTags(file.tags);
|
|
90
|
+
}
|
|
91
|
+
/** Returns the last 64 length hex string in a URL */
|
|
92
|
+
export function getSha256FromURL(url) {
|
|
93
|
+
if (typeof url === "string")
|
|
94
|
+
url = new URL(url);
|
|
95
|
+
const hashes = Array.from(url.pathname.matchAll(/[0-9a-f]{64}/gi));
|
|
96
|
+
if (hashes.length > 0)
|
|
97
|
+
return hashes[hashes.length - 1][0];
|
|
98
|
+
return;
|
|
99
|
+
}
|
package/dist/helpers/filter.d.ts
CHANGED
|
@@ -6,5 +6,9 @@ import { Filter, NostrEvent } from "nostr-tools";
|
|
|
6
6
|
export declare function matchFilter(filter: Filter, event: NostrEvent): boolean;
|
|
7
7
|
/** Copied from nostr-tools */
|
|
8
8
|
export declare function matchFilters(filters: Filter[], event: NostrEvent): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Copied from nostr-tools and modified to support undefined
|
|
11
|
+
*/
|
|
12
|
+
export declare function mergeFilters(...filters: Filter[]): Filter;
|
|
9
13
|
/** Check if two filters are equal */
|
|
10
14
|
export declare function isFilterEqual(a: Filter | Filter[], b: Filter | Filter[]): boolean;
|
package/dist/helpers/filter.js
CHANGED
|
@@ -17,7 +17,7 @@ export function matchFilter(filter, event) {
|
|
|
17
17
|
for (let f in filter) {
|
|
18
18
|
if (f[0] === "#") {
|
|
19
19
|
let tagName = f.slice(1);
|
|
20
|
-
let values = filter[
|
|
20
|
+
let values = filter[f];
|
|
21
21
|
if (values) {
|
|
22
22
|
const tags = getIndexableTags(event);
|
|
23
23
|
if (values.some((v) => tags.has(tagName + ":" + v)) === false)
|
|
@@ -40,6 +40,39 @@ export function matchFilters(filters, event) {
|
|
|
40
40
|
}
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Copied from nostr-tools and modified to support undefined
|
|
45
|
+
*/
|
|
46
|
+
export function mergeFilters(...filters) {
|
|
47
|
+
let result = {};
|
|
48
|
+
for (let i = 0; i < filters.length; i++) {
|
|
49
|
+
let filter = filters[i];
|
|
50
|
+
Object.entries(filter).forEach(([property, values]) => {
|
|
51
|
+
// skip undefined
|
|
52
|
+
if (values === undefined)
|
|
53
|
+
return;
|
|
54
|
+
if (property === "kinds" || property === "ids" || property === "authors" || property[0] === "#") {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
result[property] = result[property] || [];
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
for (let v = 0; v < values.length; v++) {
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
let value = values[v];
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
if (!result[property].includes(value))
|
|
63
|
+
result[property].push(value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
if (filter.limit && (!result.limit || filter.limit > result.limit))
|
|
68
|
+
result.limit = filter.limit;
|
|
69
|
+
if (filter.until && (!result.until || filter.until > result.until))
|
|
70
|
+
result.until = filter.until;
|
|
71
|
+
if (filter.since && (!result.since || filter.since < result.since))
|
|
72
|
+
result.since = filter.since;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
43
76
|
/** Check if two filters are equal */
|
|
44
77
|
export function isFilterEqual(a, b) {
|
|
45
78
|
return equal(a, b);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NostrEvent, UnsignedEvent } from "nostr-tools";
|
|
2
|
+
import { HiddenContentSigner } from "./hidden-content.js";
|
|
3
|
+
export declare const GiftWrapSealSymbol: unique symbol;
|
|
4
|
+
export declare const GiftWrapEventSymbol: unique symbol;
|
|
5
|
+
/** Returns the unsigned seal event in a gift-wrap event */
|
|
6
|
+
export declare function getGiftWrapSeal(gift: NostrEvent): NostrEvent | undefined;
|
|
7
|
+
/** Returns the unsigned event in the gift-wrap seal */
|
|
8
|
+
export declare function getGiftWrapEvent(gift: NostrEvent): UnsignedEvent | undefined;
|
|
9
|
+
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
10
|
+
export declare function isGiftWrapLocked(gift: NostrEvent): boolean;
|
|
11
|
+
/** Unlocks and returns the unsigned seal event in a gift-wrap */
|
|
12
|
+
export declare function unlockGiftWrap(gift: NostrEvent, signer: HiddenContentSigner): Promise<UnsignedEvent>;
|