applesauce-common 0.0.0-next-20251203172109
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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/blueprints/app-data.d.ts +5 -0
- package/dist/blueprints/app-data.js +10 -0
- package/dist/blueprints/calendar.d.ts +5 -0
- package/dist/blueprints/calendar.js +7 -0
- package/dist/blueprints/channels.d.ts +6 -0
- package/dist/blueprints/channels.js +13 -0
- package/dist/blueprints/comment.d.ts +12 -0
- package/dist/blueprints/comment.js +15 -0
- package/dist/blueprints/delete.d.ts +9 -0
- package/dist/blueprints/delete.js +14 -0
- package/dist/blueprints/file-metadata.d.ts +8 -0
- package/dist/blueprints/file-metadata.js +11 -0
- package/dist/blueprints/follow-set.d.ts +11 -0
- package/dist/blueprints/follow-set.js +21 -0
- package/dist/blueprints/gift-wrap.d.ts +5 -0
- package/dist/blueprints/gift-wrap.js +6 -0
- package/dist/blueprints/group.d.ts +9 -0
- package/dist/blueprints/group.js +17 -0
- package/dist/blueprints/highlight.d.ts +20 -0
- package/dist/blueprints/highlight.js +12 -0
- package/dist/blueprints/index.d.ts +23 -0
- package/dist/blueprints/index.js +24 -0
- package/dist/blueprints/legacy-message.d.ts +7 -0
- package/dist/blueprints/legacy-message.js +29 -0
- package/dist/blueprints/live-stream.d.ts +6 -0
- package/dist/blueprints/live-stream.js +9 -0
- package/dist/blueprints/note.d.ts +16 -0
- package/dist/blueprints/note.js +30 -0
- package/dist/blueprints/picture-post.d.ts +12 -0
- package/dist/blueprints/picture-post.js +17 -0
- package/dist/blueprints/poll.d.ts +41 -0
- package/dist/blueprints/poll.js +33 -0
- package/dist/blueprints/profile.d.ts +3 -0
- package/dist/blueprints/profile.js +7 -0
- package/dist/blueprints/reaction.d.ts +10 -0
- package/dist/blueprints/reaction.js +14 -0
- package/dist/blueprints/share.d.ts +12 -0
- package/dist/blueprints/share.js +25 -0
- package/dist/blueprints/stream.d.ts +6 -0
- package/dist/blueprints/stream.js +7 -0
- package/dist/blueprints/torrent.d.ts +23 -0
- package/dist/blueprints/torrent.js +25 -0
- package/dist/blueprints/wrapped-message.d.ts +20 -0
- package/dist/blueprints/wrapped-message.js +64 -0
- package/dist/helpers/app-data.d.ts +39 -0
- package/dist/helpers/app-data.js +68 -0
- package/dist/helpers/app-handler.d.ts +22 -0
- package/dist/helpers/app-handler.js +67 -0
- package/dist/helpers/article.d.ts +14 -0
- package/dist/helpers/article.js +24 -0
- package/dist/helpers/blossom.d.ts +11 -0
- package/dist/helpers/blossom.js +40 -0
- package/dist/helpers/bolt11.d.ts +10 -0
- package/dist/helpers/bolt11.js +17 -0
- package/dist/helpers/bookmark.d.ts +30 -0
- package/dist/helpers/bookmark.js +96 -0
- package/dist/helpers/calendar-event.d.ts +39 -0
- package/dist/helpers/calendar-event.js +121 -0
- package/dist/helpers/calendar-rsvp.d.ts +15 -0
- package/dist/helpers/calendar-rsvp.js +38 -0
- package/dist/helpers/calendar.d.ts +6 -0
- package/dist/helpers/calendar.js +11 -0
- package/dist/helpers/channels.d.ts +13 -0
- package/dist/helpers/channels.js +27 -0
- package/dist/helpers/comment.d.ts +47 -0
- package/dist/helpers/comment.js +185 -0
- package/dist/helpers/content.d.ts +3 -0
- package/dist/helpers/content.js +8 -0
- package/dist/helpers/emoji.d.ts +21 -0
- package/dist/helpers/emoji.js +34 -0
- package/dist/helpers/encrypted-content-cache.d.ts +22 -0
- package/dist/helpers/encrypted-content-cache.js +138 -0
- package/dist/helpers/file-metadata.d.ts +55 -0
- package/dist/helpers/file-metadata.js +130 -0
- package/dist/helpers/gift-wrap.d.ts +66 -0
- package/dist/helpers/gift-wrap.js +204 -0
- package/dist/helpers/groups-helper.d.ts +6 -0
- package/dist/helpers/groups-helper.js +9 -0
- package/dist/helpers/groups.d.ts +26 -0
- package/dist/helpers/groups.js +49 -0
- package/dist/helpers/hashtag.d.ts +2 -0
- package/dist/helpers/hashtag.js +7 -0
- package/dist/helpers/highlight.d.ts +45 -0
- package/dist/helpers/highlight.js +76 -0
- package/dist/helpers/index.d.ts +37 -0
- package/dist/helpers/index.js +37 -0
- package/dist/helpers/legacy-messages.d.ts +31 -0
- package/dist/helpers/legacy-messages.js +49 -0
- package/dist/helpers/lists.d.ts +58 -0
- package/dist/helpers/lists.js +110 -0
- package/dist/helpers/lnurl.d.ts +8 -0
- package/dist/helpers/lnurl.js +44 -0
- package/dist/helpers/mailboxes.d.ts +7 -0
- package/dist/helpers/mailboxes.js +49 -0
- package/dist/helpers/messages.d.ts +31 -0
- package/dist/helpers/messages.js +57 -0
- package/dist/helpers/mute.d.ts +33 -0
- package/dist/helpers/mute.js +111 -0
- package/dist/helpers/picture-post.d.ts +5 -0
- package/dist/helpers/picture-post.js +6 -0
- package/dist/helpers/poll.d.ts +46 -0
- package/dist/helpers/poll.js +78 -0
- package/dist/helpers/reaction.d.ts +8 -0
- package/dist/helpers/reaction.js +56 -0
- package/dist/helpers/relay-discovery.d.ts +87 -0
- package/dist/helpers/relay-discovery.js +126 -0
- package/dist/helpers/reports.d.ts +28 -0
- package/dist/helpers/reports.js +38 -0
- package/dist/helpers/share.d.ts +19 -0
- package/dist/helpers/share.js +58 -0
- package/dist/helpers/stream-chat.d.ts +4 -0
- package/dist/helpers/stream-chat.js +9 -0
- package/dist/helpers/stream.d.ts +31 -0
- package/dist/helpers/stream.js +81 -0
- package/dist/helpers/threading.d.ts +55 -0
- package/dist/helpers/threading.js +94 -0
- package/dist/helpers/torrent.d.ts +55 -0
- package/dist/helpers/torrent.js +270 -0
- package/dist/helpers/user-status.d.ts +18 -0
- package/dist/helpers/user-status.js +22 -0
- package/dist/helpers/wrapped-messages.d.ts +14 -0
- package/dist/helpers/wrapped-messages.js +23 -0
- package/dist/helpers/zap.d.ts +46 -0
- package/dist/helpers/zap.js +125 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/models/blossom.d.ts +11 -0
- package/dist/models/blossom.js +18 -0
- package/dist/models/bookmarks.d.ts +8 -0
- package/dist/models/bookmarks.js +24 -0
- package/dist/models/calendar.d.ts +6 -0
- package/dist/models/calendar.js +15 -0
- package/dist/models/channels.d.ts +11 -0
- package/dist/models/channels.js +61 -0
- package/dist/models/comments.d.ts +11 -0
- package/dist/models/comments.js +17 -0
- package/dist/models/gift-wrap.d.ts +7 -0
- package/dist/models/gift-wrap.js +20 -0
- package/dist/models/index.d.ts +15 -0
- package/dist/models/index.js +16 -0
- package/dist/models/legacy-messages.d.ts +14 -0
- package/dist/models/legacy-messages.js +64 -0
- package/dist/models/mutes.d.ts +16 -0
- package/dist/models/mutes.js +34 -0
- package/dist/models/pins.d.ts +4 -0
- package/dist/models/pins.js +10 -0
- package/dist/models/reactions.d.ts +11 -0
- package/dist/models/reactions.js +21 -0
- package/dist/models/thread.d.ts +33 -0
- package/dist/models/thread.js +93 -0
- package/dist/models/user-status.d.ts +11 -0
- package/dist/models/user-status.js +32 -0
- package/dist/models/wrapped-messages.d.ts +31 -0
- package/dist/models/wrapped-messages.js +76 -0
- package/dist/models/zaps.d.ts +9 -0
- package/dist/models/zaps.js +26 -0
- package/dist/operations/app-data.d.ts +6 -0
- package/dist/operations/app-data.js +21 -0
- package/dist/operations/blossom.d.ts +5 -0
- package/dist/operations/blossom.js +13 -0
- package/dist/operations/calendar-event.d.ts +34 -0
- package/dist/operations/calendar-event.js +72 -0
- package/dist/operations/calendar-rsvp.d.ts +10 -0
- package/dist/operations/calendar-rsvp.js +35 -0
- package/dist/operations/calendar.d.ts +9 -0
- package/dist/operations/calendar.js +15 -0
- package/dist/operations/channel.d.ts +4 -0
- package/dist/operations/channel.js +10 -0
- package/dist/operations/client.d.ts +4 -0
- package/dist/operations/client.js +23 -0
- package/dist/operations/comment.d.ts +4 -0
- package/dist/operations/comment.js +11 -0
- package/dist/operations/file-metadata.d.ts +4 -0
- package/dist/operations/file-metadata.js +21 -0
- package/dist/operations/geohash.d.ts +5 -0
- package/dist/operations/geohash.js +17 -0
- package/dist/operations/gift-wrap.d.ts +13 -0
- package/dist/operations/gift-wrap.js +93 -0
- package/dist/operations/group.d.ts +11 -0
- package/dist/operations/group.js +34 -0
- package/dist/operations/hashtags.d.ts +7 -0
- package/dist/operations/hashtags.js +17 -0
- package/dist/operations/highlight.d.ts +18 -0
- package/dist/operations/highlight.js +47 -0
- package/dist/operations/index.d.ts +28 -0
- package/dist/operations/index.js +28 -0
- package/dist/operations/legacy-message.d.ts +6 -0
- package/dist/operations/legacy-message.js +13 -0
- package/dist/operations/list.d.ts +7 -0
- package/dist/operations/list.js +14 -0
- package/dist/operations/live-stream.d.ts +4 -0
- package/dist/operations/live-stream.js +11 -0
- package/dist/operations/media-attachment.d.ts +4 -0
- package/dist/operations/media-attachment.js +12 -0
- package/dist/operations/note.d.ts +9 -0
- package/dist/operations/note.js +42 -0
- package/dist/operations/picture-post.d.ts +4 -0
- package/dist/operations/picture-post.js +14 -0
- package/dist/operations/poll-response.d.ts +9 -0
- package/dist/operations/poll-response.js +20 -0
- package/dist/operations/poll.d.ts +19 -0
- package/dist/operations/poll.js +42 -0
- package/dist/operations/reaction.d.ts +7 -0
- package/dist/operations/reaction.js +39 -0
- package/dist/operations/share.d.ts +8 -0
- package/dist/operations/share.js +34 -0
- package/dist/operations/stream-chat.d.ts +7 -0
- package/dist/operations/stream-chat.js +27 -0
- package/dist/operations/stream.d.ts +41 -0
- package/dist/operations/stream.js +83 -0
- package/dist/operations/tag/bookmarks.d.ts +6 -0
- package/dist/operations/tag/bookmarks.js +20 -0
- package/dist/operations/tag/index.d.ts +1 -0
- package/dist/operations/tag/index.js +1 -0
- package/dist/operations/torrent.d.ts +33 -0
- package/dist/operations/torrent.js +66 -0
- package/dist/operations/wrapped-message.d.ts +12 -0
- package/dist/operations/wrapped-message.js +28 -0
- package/dist/operations/zap-split.d.ts +10 -0
- package/dist/operations/zap-split.js +20 -0
- package/dist/register.d.ts +11 -0
- package/dist/register.js +13 -0
- package/package.json +91 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { safeParse } from "applesauce-core/helpers/json";
|
|
3
|
+
import { map } from "rxjs";
|
|
4
|
+
import { getChannelMetadataContent } from "../helpers/channels.js";
|
|
5
|
+
/** A model that returns a map of hidden messages Map<id, reason> */
|
|
6
|
+
export function ChannelHiddenModel(channel, authors = []) {
|
|
7
|
+
return (events) => {
|
|
8
|
+
const hidden = new Map();
|
|
9
|
+
return events
|
|
10
|
+
.filters([{ kinds: [kinds.ChannelHideMessage], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
|
|
11
|
+
.pipe(map((event) => {
|
|
12
|
+
const reason = safeParse(event.content)?.reason;
|
|
13
|
+
for (const tag of event.tags) {
|
|
14
|
+
if (tag[0] === "e" && tag[1])
|
|
15
|
+
hidden.set(tag[1], reason ?? "");
|
|
16
|
+
}
|
|
17
|
+
return hidden;
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** A model that returns all messages in a channel */
|
|
22
|
+
export function ChannelMessagesModel(channel) {
|
|
23
|
+
return (events) => events.timeline([{ kinds: [kinds.ChannelMessage], "#e": [channel.id] }]);
|
|
24
|
+
}
|
|
25
|
+
/** A model that returns the latest parsed metadata */
|
|
26
|
+
export function ChannelMetadataModel(channel) {
|
|
27
|
+
return (events) => {
|
|
28
|
+
const filters = [
|
|
29
|
+
{ ids: [channel.id] },
|
|
30
|
+
{ kinds: [kinds.ChannelMetadata], "#e": [channel.id], authors: [channel.pubkey] },
|
|
31
|
+
];
|
|
32
|
+
let latest = channel;
|
|
33
|
+
return events.filters(filters).pipe(map((event) => {
|
|
34
|
+
try {
|
|
35
|
+
if (event.pubkey === latest.pubkey && event.created_at > latest.created_at) {
|
|
36
|
+
latest = event;
|
|
37
|
+
}
|
|
38
|
+
return getChannelMetadataContent(latest);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** A model that returns a map of muted users Map<pubkey, reason> */
|
|
47
|
+
export function ChannelMutedModel(channel, authors = []) {
|
|
48
|
+
return (events) => {
|
|
49
|
+
const muted = new Map();
|
|
50
|
+
return events
|
|
51
|
+
.filters([{ kinds: [kinds.ChannelMuteUser], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
|
|
52
|
+
.pipe(map((event) => {
|
|
53
|
+
const reason = safeParse(event.content)?.reason;
|
|
54
|
+
for (const tag of event.tags) {
|
|
55
|
+
if (tag[0] === "p" && tag[1])
|
|
56
|
+
muted.set(tag[1], reason ?? "");
|
|
57
|
+
}
|
|
58
|
+
return muted;
|
|
59
|
+
}));
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
import { type Observable } from "rxjs";
|
|
4
|
+
/** A model that returns all NIP-22 comment replies for the event */
|
|
5
|
+
export declare function CommentsModel(parent: NostrEvent): Model<NostrEvent[]>;
|
|
6
|
+
declare module "applesauce-core/event-store" {
|
|
7
|
+
interface EventModels {
|
|
8
|
+
/** Subscribe to an event's comments */
|
|
9
|
+
comments(event: NostrEvent): Observable<NostrEvent[]>;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getReplaceableAddress, isAddressableKind } from "applesauce-core/helpers/event";
|
|
2
|
+
import { COMMENT_KIND } from "../helpers/comment.js";
|
|
3
|
+
// Import EventModels as a value (class) to modify its prototype
|
|
4
|
+
import { EventModels } from "applesauce-core/event-store";
|
|
5
|
+
/** A model that returns all NIP-22 comment replies for the event */
|
|
6
|
+
export function CommentsModel(parent) {
|
|
7
|
+
return (events) => {
|
|
8
|
+
const filters = [{ kinds: [COMMENT_KIND], "#e": [parent.id] }];
|
|
9
|
+
if (isAddressableKind(parent.kind))
|
|
10
|
+
filters.push({ kinds: [COMMENT_KIND], "#a": [getReplaceableAddress(parent)] });
|
|
11
|
+
return events.timeline(filters);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
// Register this model with EventModels
|
|
15
|
+
EventModels.prototype.comments = function (event) {
|
|
16
|
+
return this.model(CommentsModel, event);
|
|
17
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
import { Rumor } from "../helpers/gift-wrap.js";
|
|
4
|
+
/** A model that returns all gift wrap events for a pubkey, optionally filtered by locked status */
|
|
5
|
+
export declare function GiftWrapsModel(pubkey: string, unlocked?: boolean): Model<NostrEvent[]>;
|
|
6
|
+
/** A model that returns the rumor event of a gift wrap event when its unlocked */
|
|
7
|
+
export declare function GiftWrapRumorModel(gift: NostrEvent | string): Model<Rumor | undefined>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { watchEventsUpdates, watchEventUpdates } from "applesauce-core/observable";
|
|
3
|
+
import { identity, map, of } from "rxjs";
|
|
4
|
+
import { getGiftWrapRumor, isGiftWrapUnlocked } from "../helpers/gift-wrap.js";
|
|
5
|
+
/** A model that returns all gift wrap events for a pubkey, optionally filtered by locked status */
|
|
6
|
+
export function GiftWrapsModel(pubkey, unlocked) {
|
|
7
|
+
return (store) => store.timeline({ kinds: [kinds.GiftWrap], "#p": [pubkey] }).pipe(
|
|
8
|
+
// Update the timeline when events are updated
|
|
9
|
+
watchEventsUpdates(store),
|
|
10
|
+
// If unlock is specified filter on unlocked status
|
|
11
|
+
unlocked !== undefined ? map((events) => events.filter((e) => isGiftWrapUnlocked(e) === unlocked)) : identity);
|
|
12
|
+
}
|
|
13
|
+
/** A model that returns the rumor event of a gift wrap event when its unlocked */
|
|
14
|
+
export function GiftWrapRumorModel(gift) {
|
|
15
|
+
return (events) => (typeof gift === "string" ? events.event(gift) : of(gift)).pipe(
|
|
16
|
+
// Listen for updates to the event
|
|
17
|
+
watchEventUpdates(events),
|
|
18
|
+
// Get the rumor event
|
|
19
|
+
map((event) => event && getGiftWrapRumor(event)));
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./blossom.js";
|
|
2
|
+
export * from "./bookmarks.js";
|
|
3
|
+
export * from "./calendar.js";
|
|
4
|
+
export * from "./channels.js";
|
|
5
|
+
export * from "./comments.js";
|
|
6
|
+
export * from "./legacy-messages.js";
|
|
7
|
+
export * from "./mutes.js";
|
|
8
|
+
export * from "./pins.js";
|
|
9
|
+
export * from "./reactions.js";
|
|
10
|
+
export * from "./thread.js";
|
|
11
|
+
export * from "./user-status.js";
|
|
12
|
+
export * from "./wrapped-messages.js";
|
|
13
|
+
export * from "./zaps.js";
|
|
14
|
+
export * from "./gift-wrap.js";
|
|
15
|
+
import "../register.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./blossom.js";
|
|
2
|
+
export * from "./bookmarks.js";
|
|
3
|
+
export * from "./calendar.js";
|
|
4
|
+
export * from "./channels.js";
|
|
5
|
+
export * from "./comments.js";
|
|
6
|
+
export * from "./legacy-messages.js";
|
|
7
|
+
export * from "./mutes.js";
|
|
8
|
+
export * from "./pins.js";
|
|
9
|
+
export * from "./reactions.js";
|
|
10
|
+
export * from "./thread.js";
|
|
11
|
+
export * from "./user-status.js";
|
|
12
|
+
export * from "./wrapped-messages.js";
|
|
13
|
+
export * from "./zaps.js";
|
|
14
|
+
export * from "./gift-wrap.js";
|
|
15
|
+
// Register the common models with the event store
|
|
16
|
+
import "../register.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
/** A model that returns all legacy message groups (1-1) that a pubkey is participating in */
|
|
4
|
+
export declare function LegacyMessagesGroups(self: string): Model<{
|
|
5
|
+
id: string;
|
|
6
|
+
participants: string[];
|
|
7
|
+
lastMessage: NostrEvent;
|
|
8
|
+
}[]>;
|
|
9
|
+
/** Returns all legacy direct messages in a group */
|
|
10
|
+
export declare function LegacyMessagesGroup(self: string, correspondent: string): Model<NostrEvent[]>;
|
|
11
|
+
/** Returns an array of legacy messages that have replies */
|
|
12
|
+
export declare function LegacyMessageThreads(self: string, correspondent: string): Model<NostrEvent[]>;
|
|
13
|
+
/** Returns all the legacy direct messages that are replies to a given message */
|
|
14
|
+
export declare function LegacyMessageReplies(self: string, message: NostrEvent): Model<NostrEvent[]>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { hasNameValueTag } from "applesauce-core/helpers/event";
|
|
3
|
+
import { map } from "rxjs";
|
|
4
|
+
import { getLegacyMessageCorrespondent, getLegacyMessageParent } from "../helpers/legacy-messages.js";
|
|
5
|
+
import { getConversationIdentifierFromMessage, getConversationParticipants } from "../helpers/messages.js";
|
|
6
|
+
/** A model that returns all legacy message groups (1-1) that a pubkey is participating in */
|
|
7
|
+
export function LegacyMessagesGroups(self) {
|
|
8
|
+
return (store) => store.timeline({ kinds: [kinds.EncryptedDirectMessage], "#p": [self] }).pipe(map((messages) => {
|
|
9
|
+
const groups = {};
|
|
10
|
+
for (const message of messages) {
|
|
11
|
+
const id = getConversationIdentifierFromMessage(message);
|
|
12
|
+
if (!groups[id] || groups[id].created_at < message.created_at)
|
|
13
|
+
groups[id] = message;
|
|
14
|
+
}
|
|
15
|
+
return Object.values(groups).map((message) => ({
|
|
16
|
+
id: getConversationIdentifierFromMessage(message),
|
|
17
|
+
participants: getConversationParticipants(message),
|
|
18
|
+
lastMessage: message,
|
|
19
|
+
}));
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
/** Returns all legacy direct messages in a group */
|
|
23
|
+
export function LegacyMessagesGroup(self, correspondent) {
|
|
24
|
+
return (store) => store.timeline([
|
|
25
|
+
{
|
|
26
|
+
kinds: [kinds.EncryptedDirectMessage],
|
|
27
|
+
"#p": [self],
|
|
28
|
+
authors: [correspondent],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
kinds: [kinds.EncryptedDirectMessage],
|
|
32
|
+
"#p": [correspondent],
|
|
33
|
+
authors: [self],
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
/** Returns an array of legacy messages that have replies */
|
|
38
|
+
export function LegacyMessageThreads(self, correspondent) {
|
|
39
|
+
return (store) => store.model(LegacyMessagesGroup, self, correspondent).pipe(map((messages) => messages.filter((message) =>
|
|
40
|
+
// Only select messages that are not replies
|
|
41
|
+
!getLegacyMessageParent(message) &&
|
|
42
|
+
// Check if message has any replies
|
|
43
|
+
messages.some((m) => hasNameValueTag(m, "e", message.id)))));
|
|
44
|
+
}
|
|
45
|
+
/** Returns all the legacy direct messages that are replies to a given message */
|
|
46
|
+
export function LegacyMessageReplies(self, message) {
|
|
47
|
+
const correspondent = getLegacyMessageCorrespondent(message, self);
|
|
48
|
+
if (!correspondent)
|
|
49
|
+
throw new Error("Legacy message has no correspondent");
|
|
50
|
+
return (store) => store.timeline([
|
|
51
|
+
{
|
|
52
|
+
kinds: [kinds.EncryptedDirectMessage],
|
|
53
|
+
"#p": [self],
|
|
54
|
+
authors: [correspondent],
|
|
55
|
+
"#e": [message.id],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
kinds: [kinds.EncryptedDirectMessage],
|
|
59
|
+
"#p": [correspondent],
|
|
60
|
+
authors: [self],
|
|
61
|
+
"#e": [message.id],
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { ProfilePointer } from "applesauce-core/helpers/pointers";
|
|
3
|
+
import { type Observable } from "rxjs";
|
|
4
|
+
import { Mutes } from "../helpers/mute.js";
|
|
5
|
+
/** A model that returns all a users muted things */
|
|
6
|
+
export declare function MuteModel(user: string | ProfilePointer): Model<Mutes | undefined>;
|
|
7
|
+
/** A model that returns all a users public muted things */
|
|
8
|
+
export declare function PublicMuteModel(pubkey: string): Model<Mutes | undefined>;
|
|
9
|
+
/** A model that returns all a users hidden muted things */
|
|
10
|
+
export declare function HiddenMuteModel(pubkey: string): Model<Mutes | null | undefined>;
|
|
11
|
+
declare module "applesauce-core/event-store" {
|
|
12
|
+
interface EventModels {
|
|
13
|
+
/** Subscribe to a users mutes */
|
|
14
|
+
mutes(user: string | ProfilePointer): Observable<Mutes | undefined>;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { watchEventUpdates } from "applesauce-core/observable";
|
|
3
|
+
import { map } from "rxjs/operators";
|
|
4
|
+
import { getHiddenMutedThings, getMutedThings, getPublicMutedThings } from "../helpers/mute.js";
|
|
5
|
+
// Import EventModels as a value (class) to modify its prototype
|
|
6
|
+
import { EventModels } from "applesauce-core/event-store";
|
|
7
|
+
/** A model that returns all a users muted things */
|
|
8
|
+
export function MuteModel(user) {
|
|
9
|
+
if (typeof user === "string")
|
|
10
|
+
user = { pubkey: user };
|
|
11
|
+
return (events) => events.replaceable({ kind: kinds.Mutelist, pubkey: user.pubkey, relays: user.relays }).pipe(
|
|
12
|
+
// listen for event updates (hidden tags unlocked)
|
|
13
|
+
watchEventUpdates(events),
|
|
14
|
+
// Get all muted things
|
|
15
|
+
map((event) => event && getMutedThings(event)));
|
|
16
|
+
}
|
|
17
|
+
/** A model that returns all a users public muted things */
|
|
18
|
+
export function PublicMuteModel(pubkey) {
|
|
19
|
+
return (events) => events.replaceable(kinds.Mutelist, pubkey).pipe(map((event) => event && getPublicMutedThings(event)));
|
|
20
|
+
}
|
|
21
|
+
/** A model that returns all a users hidden muted things */
|
|
22
|
+
export function HiddenMuteModel(pubkey) {
|
|
23
|
+
return (events) => events.replaceable(kinds.Mutelist, pubkey).pipe(
|
|
24
|
+
// listen for event updates (hidden tags unlocked)
|
|
25
|
+
watchEventUpdates(events),
|
|
26
|
+
// Get hidden muted things
|
|
27
|
+
map((event) => event && getHiddenMutedThings(event)));
|
|
28
|
+
}
|
|
29
|
+
// Register this model with EventModels
|
|
30
|
+
EventModels.prototype.mutes = function (user) {
|
|
31
|
+
if (typeof user === "string")
|
|
32
|
+
user = { pubkey: user };
|
|
33
|
+
return this.model(MuteModel, user);
|
|
34
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { EventPointer } from "applesauce-core/helpers/pointers";
|
|
3
|
+
/** A model that returns all pinned pointers for a user */
|
|
4
|
+
export declare function UserPinnedModel(pubkey: string): Model<EventPointer[] | undefined>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { getEventPointerFromETag } from "applesauce-core/helpers/pointers";
|
|
3
|
+
import { isETag, processTags } from "applesauce-core/helpers/tags";
|
|
4
|
+
import { map } from "rxjs/operators";
|
|
5
|
+
/** A model that returns all pinned pointers for a user */
|
|
6
|
+
export function UserPinnedModel(pubkey) {
|
|
7
|
+
return (events) => events
|
|
8
|
+
.replaceable(kinds.Pinlist, pubkey)
|
|
9
|
+
.pipe(map((event) => event && processTags(event.tags.filter(isETag), getEventPointerFromETag)));
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
+
import { Model } from "applesauce-core/event-store";
|
|
3
|
+
import { type Observable } from "rxjs";
|
|
4
|
+
/** A model that returns all reactions to an event (supports replaceable events) */
|
|
5
|
+
export declare function ReactionsModel(event: NostrEvent): Model<NostrEvent[]>;
|
|
6
|
+
declare module "applesauce-core/event-store" {
|
|
7
|
+
interface EventModels {
|
|
8
|
+
/** Subscribe to an event's reactions */
|
|
9
|
+
reactions(event: NostrEvent): Observable<NostrEvent[]>;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getEventUID, isReplaceable, kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
// Import EventModels as a value (class) to modify its prototype
|
|
3
|
+
import { EventModels } from "applesauce-core/event-store";
|
|
4
|
+
/** A model that returns all reactions to an event (supports replaceable events) */
|
|
5
|
+
export function ReactionsModel(event) {
|
|
6
|
+
return (events) => events.timeline(isReplaceable(event.kind)
|
|
7
|
+
? [
|
|
8
|
+
{ kinds: [kinds.Reaction], "#e": [event.id] },
|
|
9
|
+
{ kinds: [kinds.Reaction], "#a": [getEventUID(event)] },
|
|
10
|
+
]
|
|
11
|
+
: [
|
|
12
|
+
{
|
|
13
|
+
kinds: [kinds.Reaction],
|
|
14
|
+
"#e": [event.id],
|
|
15
|
+
},
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
// Register this model with EventModels
|
|
19
|
+
EventModels.prototype.reactions = function (event) {
|
|
20
|
+
return this.model(ReactionsModel, event);
|
|
21
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
import { AddressPointer, EventPointer } from "applesauce-core/helpers/pointers";
|
|
4
|
+
import { type Observable } from "rxjs";
|
|
5
|
+
import { ThreadReferences } from "../helpers/threading.js";
|
|
6
|
+
export type Thread = {
|
|
7
|
+
root?: ThreadItem;
|
|
8
|
+
all: Map<string, ThreadItem>;
|
|
9
|
+
};
|
|
10
|
+
export type ThreadItem = {
|
|
11
|
+
/** underlying nostr event */
|
|
12
|
+
event: NostrEvent;
|
|
13
|
+
refs: ThreadReferences;
|
|
14
|
+
/** the thread root, according to this event */
|
|
15
|
+
root?: ThreadItem;
|
|
16
|
+
/** the parent event this is replying to */
|
|
17
|
+
parent?: ThreadItem;
|
|
18
|
+
/** direct child replies */
|
|
19
|
+
replies: Set<ThreadItem>;
|
|
20
|
+
};
|
|
21
|
+
export type ThreadModelOptions = {
|
|
22
|
+
kinds?: number[];
|
|
23
|
+
};
|
|
24
|
+
/** A model that returns a NIP-10 thread of events */
|
|
25
|
+
export declare function ThreadModel(root: string | AddressPointer | EventPointer, opts?: ThreadModelOptions): Model<Thread>;
|
|
26
|
+
/** A model that gets all legacy and NIP-10, and NIP-22 replies for an event */
|
|
27
|
+
export declare function RepliesModel(event: NostrEvent, overrideKinds?: number[]): Model<NostrEvent[]>;
|
|
28
|
+
declare module "applesauce-core/event-store" {
|
|
29
|
+
interface EventModels {
|
|
30
|
+
/** Subscribe to a thread */
|
|
31
|
+
thread(root: string | EventPointer | AddressPointer): Observable<Thread>;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createReplaceableAddress, getEventUID, isEvent, kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { getTagValue } from "applesauce-core/helpers/event";
|
|
3
|
+
import { getCoordinateFromAddressPointer, isAddressPointer, isEventPointer, } from "applesauce-core/helpers/pointers";
|
|
4
|
+
import { isAddressableKind } from "applesauce-core/helpers/event";
|
|
5
|
+
import { map } from "rxjs/operators";
|
|
6
|
+
import { COMMENT_KIND } from "../helpers/comment.js";
|
|
7
|
+
import { getNip10References, interpretThreadTags } from "../helpers/threading.js";
|
|
8
|
+
// Import EventModels as a value (class) to modify its prototype
|
|
9
|
+
import { EventModels } from "applesauce-core/event-store";
|
|
10
|
+
const defaultOptions = {
|
|
11
|
+
kinds: [kinds.ShortTextNote],
|
|
12
|
+
};
|
|
13
|
+
/** A model that returns a NIP-10 thread of events */
|
|
14
|
+
export function ThreadModel(root, opts) {
|
|
15
|
+
const parentReferences = new Map();
|
|
16
|
+
const items = new Map();
|
|
17
|
+
const { kinds } = { ...defaultOptions, ...opts };
|
|
18
|
+
let rootUID = "";
|
|
19
|
+
const rootFilter = {};
|
|
20
|
+
const replyFilter = { kinds };
|
|
21
|
+
if (isAddressPointer(root)) {
|
|
22
|
+
rootUID = getCoordinateFromAddressPointer(root);
|
|
23
|
+
rootFilter.kinds = [root.kind];
|
|
24
|
+
rootFilter.authors = [root.pubkey];
|
|
25
|
+
rootFilter["#d"] = [root.identifier];
|
|
26
|
+
replyFilter["#a"] = [rootUID];
|
|
27
|
+
}
|
|
28
|
+
else if (typeof root === "string") {
|
|
29
|
+
rootUID = root;
|
|
30
|
+
rootFilter.ids = [root];
|
|
31
|
+
replyFilter["#e"] = [root];
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
rootUID = root.id;
|
|
35
|
+
rootFilter.ids = [root.id];
|
|
36
|
+
replyFilter["#e"] = [root.id];
|
|
37
|
+
}
|
|
38
|
+
return (events) => events.filters([rootFilter, replyFilter]).pipe(map((event) => {
|
|
39
|
+
if (!items.has(getEventUID(event))) {
|
|
40
|
+
const refs = getNip10References(event);
|
|
41
|
+
const replies = parentReferences.get(getEventUID(event)) || new Set();
|
|
42
|
+
const item = { event, refs, replies };
|
|
43
|
+
for (const child of replies) {
|
|
44
|
+
child.parent = item;
|
|
45
|
+
}
|
|
46
|
+
// add item to parent
|
|
47
|
+
if (refs.reply?.e || refs.reply?.a) {
|
|
48
|
+
let uid = refs.reply.e ? refs.reply.e.id : getCoordinateFromAddressPointer(refs.reply.a);
|
|
49
|
+
item.parent = items.get(uid);
|
|
50
|
+
if (item.parent) {
|
|
51
|
+
item.parent.replies.add(item);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// parent isn't created yet, store ref for later
|
|
55
|
+
let set = parentReferences.get(uid);
|
|
56
|
+
if (!set) {
|
|
57
|
+
set = new Set();
|
|
58
|
+
parentReferences.set(uid, set);
|
|
59
|
+
}
|
|
60
|
+
set.add(item);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// add item to map
|
|
64
|
+
items.set(getEventUID(event), item);
|
|
65
|
+
}
|
|
66
|
+
return { root: items.get(rootUID), all: items };
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
/** A model that gets all legacy and NIP-10, and NIP-22 replies for an event */
|
|
70
|
+
export function RepliesModel(event, overrideKinds) {
|
|
71
|
+
return (events) => {
|
|
72
|
+
const kinds = overrideKinds || event.kind === 1 ? [1, COMMENT_KIND] : [COMMENT_KIND];
|
|
73
|
+
const filter = { kinds };
|
|
74
|
+
if (isEvent(parent) || isEventPointer(event))
|
|
75
|
+
filter["#e"] = [event.id];
|
|
76
|
+
const address = isAddressableKind(event.kind)
|
|
77
|
+
? createReplaceableAddress(event.kind, event.pubkey, getTagValue(event, "d"))
|
|
78
|
+
: undefined;
|
|
79
|
+
if (address) {
|
|
80
|
+
filter["#a"] = [address];
|
|
81
|
+
}
|
|
82
|
+
return events.timeline(filter).pipe(map((events) => {
|
|
83
|
+
return events.filter((e) => {
|
|
84
|
+
const refs = interpretThreadTags(e.tags);
|
|
85
|
+
return refs.reply?.e?.[1] === event.id || refs.reply?.a?.[1] === address;
|
|
86
|
+
});
|
|
87
|
+
}));
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Register this model with EventModels
|
|
91
|
+
EventModels.prototype.thread = function (root) {
|
|
92
|
+
return this.model(ThreadModel, root);
|
|
93
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
import { UserStatusPointer } from "../helpers/user-status.js";
|
|
4
|
+
export type UserStatus = UserStatusPointer & {
|
|
5
|
+
event: NostrEvent;
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
/** A model that returns a parsed {@link UserStatus} for a certain type */
|
|
9
|
+
export declare function UserStatusModel(pubkey: string, type?: string): Model<UserStatus | undefined | null>;
|
|
10
|
+
/** A model that returns a directory of parsed {@link UserStatus} for a pubkey */
|
|
11
|
+
export declare function UserStatusesModel(pubkey: string): Model<Record<string, UserStatus>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getReplaceableIdentifier, kinds } from "applesauce-core/helpers/event";
|
|
2
|
+
import { map } from "rxjs";
|
|
3
|
+
import { getUserStatusPointer } from "../helpers/user-status.js";
|
|
4
|
+
/** A model that returns a parsed {@link UserStatus} for a certain type */
|
|
5
|
+
export function UserStatusModel(pubkey, type = "general") {
|
|
6
|
+
return (events) => events.replaceable(kinds.UserStatuses, pubkey, type).pipe(map((event) => {
|
|
7
|
+
if (!event)
|
|
8
|
+
return undefined;
|
|
9
|
+
const pointer = getUserStatusPointer(event);
|
|
10
|
+
if (!pointer)
|
|
11
|
+
return null;
|
|
12
|
+
return {
|
|
13
|
+
...pointer,
|
|
14
|
+
event,
|
|
15
|
+
content: event.content,
|
|
16
|
+
};
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
/** A model that returns a directory of parsed {@link UserStatus} for a pubkey */
|
|
20
|
+
export function UserStatusesModel(pubkey) {
|
|
21
|
+
return (events) => events.timeline([{ kinds: [kinds.UserStatuses], authors: [pubkey] }]).pipe(map((events) => {
|
|
22
|
+
return events.reduce((dir, event) => {
|
|
23
|
+
try {
|
|
24
|
+
const d = getReplaceableIdentifier(event);
|
|
25
|
+
return { ...dir, [d]: { event, ...getUserStatusPointer(event), content: event.content } };
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return dir;
|
|
29
|
+
}
|
|
30
|
+
}, {});
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { Rumor } from "../helpers/gift-wrap.js";
|
|
3
|
+
/**
|
|
4
|
+
* A model that returns all wrapped messages for a pubkey
|
|
5
|
+
* @param self - The pubkey of the user
|
|
6
|
+
*/
|
|
7
|
+
export declare function WrappedMessagesModel(self: string): Model<Rumor[]>;
|
|
8
|
+
/** A model that returns all conversations that a pubkey is participating in */
|
|
9
|
+
export declare function WrappedMessagesGroups(self: string): Model<{
|
|
10
|
+
id: string;
|
|
11
|
+
participants: string[];
|
|
12
|
+
lastMessage: Rumor;
|
|
13
|
+
}[]>;
|
|
14
|
+
/**
|
|
15
|
+
* A model that returns all wrapped direct messages in a conversation
|
|
16
|
+
* @param self - The pubkey of the user
|
|
17
|
+
* @param participants - A conversation identifier or a list of participant pubkeys
|
|
18
|
+
*/
|
|
19
|
+
export declare function WrappedMessagesGroup(self: string, participants: string | string[]): Model<Rumor[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns an array of root wrapped messages that have replies
|
|
22
|
+
* @param self - The pubkey of the user
|
|
23
|
+
* @param participants - A conversation identifier or a list of participant pubkeys
|
|
24
|
+
*/
|
|
25
|
+
export declare function WrappedMessageThreads(self: string, participants: string | string[]): Model<Rumor[]>;
|
|
26
|
+
/**
|
|
27
|
+
* A model that returns all the gift wrapped direct messages that are replies to a given message
|
|
28
|
+
* @param self - The pubkey of the user
|
|
29
|
+
* @param message - The message to get the replies for
|
|
30
|
+
*/
|
|
31
|
+
export declare function WrappedMessageReplies(self: string, message: Rumor): Model<Rumor[]>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { watchEventsUpdates } from "applesauce-core/observable";
|
|
2
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
3
|
+
import { map } from "rxjs";
|
|
4
|
+
import { getGiftWrapRumor } from "../helpers/gift-wrap.js";
|
|
5
|
+
import { createConversationIdentifier, getConversationIdentifierFromMessage, getConversationParticipants, } from "../helpers/messages.js";
|
|
6
|
+
import { getWrappedMessageParent } from "../helpers/wrapped-messages.js";
|
|
7
|
+
/**
|
|
8
|
+
* A model that returns all wrapped messages for a pubkey
|
|
9
|
+
* @param self - The pubkey of the user
|
|
10
|
+
*/
|
|
11
|
+
export function WrappedMessagesModel(self) {
|
|
12
|
+
return (store) => store.timeline({ kinds: [kinds.GiftWrap], "#p": [self] }).pipe(
|
|
13
|
+
// Watch for updates to the gift wraps
|
|
14
|
+
watchEventsUpdates(store),
|
|
15
|
+
// Get rumors and filter out locked
|
|
16
|
+
map((rumors) => rumors
|
|
17
|
+
.map((gift) => getGiftWrapRumor(gift))
|
|
18
|
+
.filter((e) => !!e)
|
|
19
|
+
.filter((e) => e.kind === kinds.PrivateDirectMessage)
|
|
20
|
+
.sort((a, b) => b.created_at - a.created_at)));
|
|
21
|
+
}
|
|
22
|
+
/** A model that returns all conversations that a pubkey is participating in */
|
|
23
|
+
export function WrappedMessagesGroups(self) {
|
|
24
|
+
return (store) => store.model(WrappedMessagesModel, self).pipe(map((messages) => {
|
|
25
|
+
const groups = {};
|
|
26
|
+
for (const message of messages) {
|
|
27
|
+
const id = getConversationIdentifierFromMessage(message);
|
|
28
|
+
if (!groups[id] || groups[id].created_at < message.created_at)
|
|
29
|
+
groups[id] = message;
|
|
30
|
+
}
|
|
31
|
+
return Object.values(groups).map((message) => ({
|
|
32
|
+
id: getConversationIdentifierFromMessage(message),
|
|
33
|
+
participants: getConversationParticipants(message),
|
|
34
|
+
lastMessage: message,
|
|
35
|
+
}));
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A model that returns all wrapped direct messages in a conversation
|
|
40
|
+
* @param self - The pubkey of the user
|
|
41
|
+
* @param participants - A conversation identifier or a list of participant pubkeys
|
|
42
|
+
*/
|
|
43
|
+
export function WrappedMessagesGroup(self, participants) {
|
|
44
|
+
// Get the conversation identifier include the users pubkey
|
|
45
|
+
const identifier = createConversationIdentifier(self, participants);
|
|
46
|
+
return (store) => store.model(WrappedMessagesModel, self).pipe(
|
|
47
|
+
// Only select direct messages for this conversation
|
|
48
|
+
map((rumors) => rumors.filter((rumor) => rumor.kind === kinds.PrivateDirectMessage &&
|
|
49
|
+
// Only select message for this conversation (the identifier from the message will include "self")
|
|
50
|
+
getConversationIdentifierFromMessage(rumor) === identifier)));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns an array of root wrapped messages that have replies
|
|
54
|
+
* @param self - The pubkey of the user
|
|
55
|
+
* @param participants - A conversation identifier or a list of participant pubkeys
|
|
56
|
+
*/
|
|
57
|
+
export function WrappedMessageThreads(self, participants) {
|
|
58
|
+
return (store) => store.model(WrappedMessagesGroup, self, participants).pipe(
|
|
59
|
+
// Filter down messages to only include root messages that have replies
|
|
60
|
+
map((rumors) => rumors.filter((rumor) =>
|
|
61
|
+
// Only select root messages
|
|
62
|
+
!getWrappedMessageParent(rumor) &&
|
|
63
|
+
// Check if message has any replies
|
|
64
|
+
rumors.some((r) => getWrappedMessageParent(r) === rumor.id))));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A model that returns all the gift wrapped direct messages that are replies to a given message
|
|
68
|
+
* @param self - The pubkey of the user
|
|
69
|
+
* @param message - The message to get the replies for
|
|
70
|
+
*/
|
|
71
|
+
export function WrappedMessageReplies(self, message) {
|
|
72
|
+
const conversation = getConversationIdentifierFromMessage(message);
|
|
73
|
+
return (store) => store.model(WrappedMessagesGroup, self, conversation).pipe(
|
|
74
|
+
// Only select replies to this message
|
|
75
|
+
map((rumors) => rumors.filter((rumor) => getWrappedMessageParent(rumor) === message.id)));
|
|
76
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Model } from "applesauce-core/event-store";
|
|
2
|
+
import { KnownEvent, kinds } from "applesauce-core/helpers/event";
|
|
3
|
+
import { AddressPointer, EventPointer } from "applesauce-core/helpers/pointers";
|
|
4
|
+
/** A model that gets all zap events for an event */
|
|
5
|
+
export declare function EventZapsModel(id: string | EventPointer | AddressPointer): Model<KnownEvent<kinds.Zap>[]>;
|
|
6
|
+
/** A model that returns all zaps sent by a user */
|
|
7
|
+
export declare function SentZapsModel(pubkey: string): Model<KnownEvent<kinds.Zap>[]>;
|
|
8
|
+
/** A model that returns all zaps received by a user */
|
|
9
|
+
export declare function ReceivedZapsModel(pubkey: string): Model<KnownEvent<kinds.Zap>[]>;
|