applesauce-common 0.0.0-next-20251209200210 → 0.0.0-next-20251220152312
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/blueprints/__register__.d.ts +6 -0
- package/dist/blueprints/__register__.js +7 -0
- package/dist/blueprints/group-mangement.d.ts +25 -0
- package/dist/blueprints/group-mangement.js +40 -0
- package/dist/blueprints/index.d.ts +1 -0
- package/dist/blueprints/index.js +1 -0
- package/dist/casts/article.d.ts +17 -0
- package/dist/casts/article.js +41 -0
- package/dist/casts/bookmarks.d.ts +35 -0
- package/dist/casts/bookmarks.js +79 -0
- package/dist/casts/cast.d.ts +30 -0
- package/dist/casts/cast.js +67 -0
- package/dist/casts/comment.d.ts +16 -0
- package/dist/casts/comment.js +49 -0
- package/dist/casts/index.d.ts +12 -0
- package/dist/casts/index.js +12 -0
- package/dist/casts/mutes.d.ts +23 -0
- package/dist/casts/mutes.js +54 -0
- package/dist/casts/note.d.ts +17 -0
- package/dist/casts/note.js +46 -0
- package/dist/casts/profile.d.ts +16 -0
- package/dist/casts/profile.js +40 -0
- package/dist/casts/relay-lists.d.ts +33 -0
- package/dist/casts/relay-lists.js +72 -0
- package/dist/casts/share.d.ts +13 -0
- package/dist/casts/share.js +28 -0
- package/dist/casts/stream.d.ts +43 -0
- package/dist/casts/stream.js +116 -0
- package/dist/casts/user.d.ts +38 -0
- package/dist/casts/user.js +169 -0
- package/dist/casts/zap.d.ts +17 -0
- package/dist/casts/zap.js +47 -0
- package/dist/helpers/bookmark.d.ts +18 -17
- package/dist/helpers/bookmark.js +36 -49
- package/dist/helpers/encrypted-content-cache.js +23 -25
- package/dist/helpers/gift-wrap.js +11 -5
- package/dist/helpers/groups.d.ts +118 -6
- package/dist/helpers/groups.js +287 -10
- package/dist/helpers/index.d.ts +1 -1
- package/dist/helpers/index.js +1 -1
- package/dist/helpers/lists.d.ts +0 -1
- package/dist/helpers/lists.js +4 -5
- package/dist/helpers/mute.d.ts +14 -11
- package/dist/helpers/mute.js +9 -4
- package/dist/helpers/relay-list.d.ts +14 -0
- package/dist/helpers/relay-list.js +18 -0
- package/dist/helpers/stream-chat.d.ts +4 -1
- package/dist/helpers/stream-chat.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/__register__.d.ts +5 -0
- package/dist/models/__register__.js +6 -0
- package/dist/models/bookmarks.d.ts +3 -5
- package/dist/models/bookmarks.js +2 -10
- package/dist/models/index.d.ts +3 -1
- package/dist/models/index.js +4 -1
- package/dist/models/mutes.d.ts +5 -5
- package/dist/models/{relays.js → relay-lists.js} +2 -1
- package/dist/models/shares.d.ts +3 -0
- package/dist/models/shares.js +5 -0
- package/dist/models/thread.js +30 -24
- package/dist/observable/cast-stream.d.ts +8 -0
- package/dist/observable/cast-stream.js +29 -0
- package/dist/observable/chainable.d.ts +50 -0
- package/dist/observable/chainable.js +79 -0
- package/dist/observable/index.d.ts +2 -0
- package/dist/observable/index.js +2 -0
- package/dist/operations/group.d.ts +14 -1
- package/dist/operations/group.js +42 -4
- package/dist/operations/index.d.ts +1 -1
- package/dist/operations/index.js +1 -1
- package/dist/operations/tag/bookmarks.d.ts +3 -2
- package/dist/operations/tag/bookmarks.js +34 -14
- package/dist/register.d.ts +2 -11
- package/dist/register.js +2 -11
- package/package.json +12 -2
- package/dist/helpers/mailboxes.d.ts +0 -7
- package/dist/helpers/mailboxes.js +0 -49
- /package/dist/models/{relays.d.ts → relay-lists.d.ts} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getDisplayName, getProfileContent, getProfilePicture, isValidProfile } from "applesauce-core/helpers/profile";
|
|
2
|
+
import { EventCast } from "./cast.js";
|
|
3
|
+
/** Cast a kind 0 event to a Profile */
|
|
4
|
+
export class Profile extends EventCast {
|
|
5
|
+
constructor(event, store) {
|
|
6
|
+
if (!isValidProfile(event))
|
|
7
|
+
throw new Error("Invalid profile");
|
|
8
|
+
super(event, store);
|
|
9
|
+
}
|
|
10
|
+
get metadata() {
|
|
11
|
+
return getProfileContent(this.event);
|
|
12
|
+
}
|
|
13
|
+
get name() {
|
|
14
|
+
return this.metadata.name;
|
|
15
|
+
}
|
|
16
|
+
get displayName() {
|
|
17
|
+
return getDisplayName(this.metadata);
|
|
18
|
+
}
|
|
19
|
+
get about() {
|
|
20
|
+
return this.metadata.about;
|
|
21
|
+
}
|
|
22
|
+
get picture() {
|
|
23
|
+
return getProfilePicture(this.metadata);
|
|
24
|
+
}
|
|
25
|
+
get dnsIdentity() {
|
|
26
|
+
return this.metadata.nip05;
|
|
27
|
+
}
|
|
28
|
+
get website() {
|
|
29
|
+
return this.metadata.website;
|
|
30
|
+
}
|
|
31
|
+
get lud16() {
|
|
32
|
+
return this.metadata.lud16;
|
|
33
|
+
}
|
|
34
|
+
get lud06() {
|
|
35
|
+
return this.metadata.lud06;
|
|
36
|
+
}
|
|
37
|
+
get lightningAddress() {
|
|
38
|
+
return this.metadata.lud16 || this.metadata.lud06;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { HiddenContentSigner } from "applesauce-core/helpers";
|
|
2
|
+
import { kinds, KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
|
|
3
|
+
import { BlockedRelaysListEvent, FAVORITE_RELAYS_KIND, FavoriteRelaysListEvent, SearchRelaysListEvent } from "../helpers/relay-list.js";
|
|
4
|
+
import { CastRefEventStore, EventCast } from "./cast.js";
|
|
5
|
+
/** Base class for relay lists */
|
|
6
|
+
declare class RelayListBase<T extends KnownEvent<typeof FAVORITE_RELAYS_KIND | typeof kinds.SearchRelaysList | kinds.BlockedRelaysList>> extends EventCast<T> {
|
|
7
|
+
constructor(event: T, store: CastRefEventStore);
|
|
8
|
+
/** The public relays in the relay list */
|
|
9
|
+
get relays(): string[];
|
|
10
|
+
/** The hidden relays in the relay list */
|
|
11
|
+
get hidden(): string[];
|
|
12
|
+
/** An observable that updates when the hidden relays are unlocked */
|
|
13
|
+
get hidden$(): import("../observable/chainable.js").ChainableObservable<string[]>;
|
|
14
|
+
/** Whether the relay list has hidden relays */
|
|
15
|
+
get hasHidden(): boolean;
|
|
16
|
+
/** Whether the relay list is unlocked */
|
|
17
|
+
get unlocked(): boolean;
|
|
18
|
+
/** Unlocks the hidden relays on the relay list */
|
|
19
|
+
unlock(signer: HiddenContentSigner): Promise<string[]>;
|
|
20
|
+
}
|
|
21
|
+
/** Class for favorite relays lists (kind 10012) */
|
|
22
|
+
export declare class FavoriteRelays extends RelayListBase<FavoriteRelaysListEvent> {
|
|
23
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
24
|
+
}
|
|
25
|
+
/** Class for search relays lists (kind 10007) */
|
|
26
|
+
export declare class SearchRelays extends RelayListBase<SearchRelaysListEvent> {
|
|
27
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
28
|
+
}
|
|
29
|
+
/** Class for blocked relays lists (kind 10006) */
|
|
30
|
+
export declare class BlockedRelays extends RelayListBase<BlockedRelaysListEvent> {
|
|
31
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { defined, watchEventUpdates } from "applesauce-core";
|
|
2
|
+
import { hasHiddenTags, isHiddenTagsUnlocked, unlockHiddenTags } from "applesauce-core/helpers";
|
|
3
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
4
|
+
import { map, of } from "rxjs";
|
|
5
|
+
import { getRelaysFromList } from "../helpers/lists.js";
|
|
6
|
+
import { FAVORITE_RELAYS_KIND, isValidBlockedRelaysList, isValidFavoriteRelaysList, isValidSearchRelaysList, } from "../helpers/relay-list.js";
|
|
7
|
+
import { EventCast } from "./cast.js";
|
|
8
|
+
/** Base class for relay lists */
|
|
9
|
+
class RelayListBase extends EventCast {
|
|
10
|
+
constructor(event, store) {
|
|
11
|
+
if (event.kind !== FAVORITE_RELAYS_KIND &&
|
|
12
|
+
event.kind !== kinds.SearchRelaysList &&
|
|
13
|
+
event.kind !== kinds.BlockedRelaysList)
|
|
14
|
+
throw new Error(`Invalid relay list (kind ${event.kind})`);
|
|
15
|
+
super(event, store);
|
|
16
|
+
}
|
|
17
|
+
/** The public relays in the relay list */
|
|
18
|
+
get relays() {
|
|
19
|
+
return getRelaysFromList(this.event);
|
|
20
|
+
}
|
|
21
|
+
/** The hidden relays in the relay list */
|
|
22
|
+
get hidden() {
|
|
23
|
+
return getRelaysFromList(this.event, "hidden");
|
|
24
|
+
}
|
|
25
|
+
/** An observable that updates when the hidden relays are unlocked */
|
|
26
|
+
get hidden$() {
|
|
27
|
+
return this.$$ref("hidden$", (store) => of(this.event).pipe(
|
|
28
|
+
// Watch for event updates
|
|
29
|
+
watchEventUpdates(store),
|
|
30
|
+
// Get the hidden relays
|
|
31
|
+
map((event) => event && getRelaysFromList(event, "hidden")),
|
|
32
|
+
// Only emit when the hidden relays are unlocked
|
|
33
|
+
defined()));
|
|
34
|
+
}
|
|
35
|
+
/** Whether the relay list has hidden relays */
|
|
36
|
+
get hasHidden() {
|
|
37
|
+
return hasHiddenTags(this.event);
|
|
38
|
+
}
|
|
39
|
+
/** Whether the relay list is unlocked */
|
|
40
|
+
get unlocked() {
|
|
41
|
+
return isHiddenTagsUnlocked(this.event);
|
|
42
|
+
}
|
|
43
|
+
/** Unlocks the hidden relays on the relay list */
|
|
44
|
+
async unlock(signer) {
|
|
45
|
+
await unlockHiddenTags(this.event, signer);
|
|
46
|
+
return this.hidden;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Class for favorite relays lists (kind 10012) */
|
|
50
|
+
export class FavoriteRelays extends RelayListBase {
|
|
51
|
+
constructor(event, store) {
|
|
52
|
+
if (!isValidFavoriteRelaysList(event))
|
|
53
|
+
throw new Error("Invalid favorite relays list");
|
|
54
|
+
super(event, store);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Class for search relays lists (kind 10007) */
|
|
58
|
+
export class SearchRelays extends RelayListBase {
|
|
59
|
+
constructor(event, store) {
|
|
60
|
+
if (!isValidSearchRelaysList(event))
|
|
61
|
+
throw new Error("Invalid search relays list");
|
|
62
|
+
super(event, store);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Class for blocked relays lists (kind 10006) */
|
|
66
|
+
export class BlockedRelays extends RelayListBase {
|
|
67
|
+
constructor(event, store) {
|
|
68
|
+
if (!isValidBlockedRelaysList(event))
|
|
69
|
+
throw new Error("Invalid blocked relays list");
|
|
70
|
+
super(event, store);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
+
import { ShareEvent } from "../helpers/share.js";
|
|
3
|
+
import { CastRefEventStore, EventCast } from "./cast.js";
|
|
4
|
+
/** Cast class for kind 6 and 16 share events */
|
|
5
|
+
export declare class Share extends EventCast<ShareEvent> {
|
|
6
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
7
|
+
get sharedKind(): number | undefined;
|
|
8
|
+
get embedded(): import("nostr-tools").Event | undefined;
|
|
9
|
+
get sharedAddressPointer(): import("nostr-tools/nip19").AddressPointer | undefined;
|
|
10
|
+
get sharedEventPointer(): import("nostr-tools/nip19").EventPointer;
|
|
11
|
+
get sharedPointer(): import("nostr-tools/nip19").EventPointer | import("nostr-tools/nip19").AddressPointer;
|
|
12
|
+
get shared$(): import("../observable/chainable.js").ChainableObservable<import("nostr-tools").Event | undefined>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getEmbededSharedEvent, getSharedAddressPointer, getSharedEventPointer, isValidShare, } from "../helpers/share.js";
|
|
2
|
+
import { EventCast } from "./cast.js";
|
|
3
|
+
/** Cast class for kind 6 and 16 share events */
|
|
4
|
+
export class Share extends EventCast {
|
|
5
|
+
constructor(event, store) {
|
|
6
|
+
if (!isValidShare(event))
|
|
7
|
+
throw new Error("Invalid share");
|
|
8
|
+
super(event, store);
|
|
9
|
+
}
|
|
10
|
+
get sharedKind() {
|
|
11
|
+
return getSharedEventPointer(this.event)?.kind;
|
|
12
|
+
}
|
|
13
|
+
get embedded() {
|
|
14
|
+
return getEmbededSharedEvent(this.event);
|
|
15
|
+
}
|
|
16
|
+
get sharedAddressPointer() {
|
|
17
|
+
return getSharedAddressPointer(this.event);
|
|
18
|
+
}
|
|
19
|
+
get sharedEventPointer() {
|
|
20
|
+
return getSharedEventPointer(this.event);
|
|
21
|
+
}
|
|
22
|
+
get sharedPointer() {
|
|
23
|
+
return this.sharedAddressPointer || this.sharedEventPointer;
|
|
24
|
+
}
|
|
25
|
+
get shared$() {
|
|
26
|
+
return this.$$ref("shared$", (store) => store.event(this.sharedPointer));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { kinds, KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
+
import { EventPointer } from "applesauce-core/helpers/pointers";
|
|
3
|
+
import { StreamChatMessageEvent } from "../helpers/stream-chat.js";
|
|
4
|
+
import { StreamStatus } from "../helpers/stream.js";
|
|
5
|
+
import { CastRefEventStore, EventCast } from "./cast.js";
|
|
6
|
+
import { Share } from "./share.js";
|
|
7
|
+
import { Zap } from "./zap.js";
|
|
8
|
+
/** Cast a kind 30311 event to a Stream (NIP-53) */
|
|
9
|
+
export declare class Stream extends EventCast<KnownEvent<kinds.LiveEvent>> {
|
|
10
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
11
|
+
get title(): string | undefined;
|
|
12
|
+
get summary(): string | undefined;
|
|
13
|
+
get image(): string | undefined;
|
|
14
|
+
get status(): StreamStatus;
|
|
15
|
+
get host(): import("./user.js").User;
|
|
16
|
+
get participants(): import("./user.js").User[];
|
|
17
|
+
get goalPointer(): EventPointer | undefined;
|
|
18
|
+
get streamingURLs(): string[];
|
|
19
|
+
get streamingVideos(): string[];
|
|
20
|
+
get streamingAudio(): string[];
|
|
21
|
+
get recording(): string | undefined;
|
|
22
|
+
get relays(): string[] | undefined;
|
|
23
|
+
get startTime(): number | undefined;
|
|
24
|
+
get endTime(): number | undefined;
|
|
25
|
+
get viewers(): number | undefined;
|
|
26
|
+
get maxViewers(): number | undefined;
|
|
27
|
+
get hashtags(): string[];
|
|
28
|
+
/** An observable of all zaps on this stream */
|
|
29
|
+
get zaps$(): import("../observable/chainable.js").ChainableObservable<Zap[]>;
|
|
30
|
+
get shares$(): import("../observable/chainable.js").ChainableObservable<Share[]>;
|
|
31
|
+
/** An observable of all chat messages for this stream */
|
|
32
|
+
get chat$(): import("../observable/chainable.js").ChainableObservable<StreamChatMessage[]>;
|
|
33
|
+
/** An observable of the goal event if this stream has a goal */
|
|
34
|
+
get goal$(): import("../observable/chainable.js").ChainableObservable<import("nostr-tools").Event | undefined>;
|
|
35
|
+
}
|
|
36
|
+
/** A cast for a stream chat message */
|
|
37
|
+
export declare class StreamChatMessage extends EventCast<StreamChatMessageEvent> {
|
|
38
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
39
|
+
get stream(): import("nostr-tools/nip19").AddressPointer;
|
|
40
|
+
get stream$(): import("../observable/chainable.js").ChainableObservable<Stream | undefined>;
|
|
41
|
+
get zaps$(): import("../observable/chainable.js").ChainableObservable<Zap[]>;
|
|
42
|
+
get reactions$(): import("../observable/chainable.js").ChainableObservable<import("nostr-tools").Event[]>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { isAudioURL, isStreamURL, isVideoURL } from "applesauce-core/helpers";
|
|
2
|
+
import { kinds } from "applesauce-core/helpers/event";
|
|
3
|
+
import { of } from "rxjs";
|
|
4
|
+
import { getStreamChatMessageStream, isValidStreamChatMessage, } from "../helpers/stream-chat.js";
|
|
5
|
+
import { getStreamEndTime, getStreamGoalPointer, getStreamHashtags, getStreamHost, getStreamImage, getStreamMaxViewers, getStreamParticipants, getStreamRecording, getStreamRelays, getStreamStartTime, getStreamStatus, getStreamStreamingURLs, getStreamSummary, getStreamTitle, getStreamViewers, } from "../helpers/stream.js";
|
|
6
|
+
import { ReactionsModel } from "../models/reactions.js";
|
|
7
|
+
import { SharesModel } from "../models/shares.js";
|
|
8
|
+
import { StreamChatMessagesModel } from "../models/stream.js";
|
|
9
|
+
import { EventZapsModel } from "../models/zaps.js";
|
|
10
|
+
import { castEventStream, castTimelineStream } from "../observable/cast-stream.js";
|
|
11
|
+
import { EventCast } from "./cast.js";
|
|
12
|
+
import { Share } from "./share.js";
|
|
13
|
+
import { Zap } from "./zap.js";
|
|
14
|
+
import { castUser } from "./user.js";
|
|
15
|
+
function isValidStream(event) {
|
|
16
|
+
return event.kind === kinds.LiveEvent;
|
|
17
|
+
}
|
|
18
|
+
/** Cast a kind 30311 event to a Stream (NIP-53) */
|
|
19
|
+
export class Stream extends EventCast {
|
|
20
|
+
constructor(event, store) {
|
|
21
|
+
if (!isValidStream(event))
|
|
22
|
+
throw new Error("Invalid stream");
|
|
23
|
+
super(event, store);
|
|
24
|
+
}
|
|
25
|
+
get title() {
|
|
26
|
+
return getStreamTitle(this.event);
|
|
27
|
+
}
|
|
28
|
+
get summary() {
|
|
29
|
+
return getStreamSummary(this.event);
|
|
30
|
+
}
|
|
31
|
+
get image() {
|
|
32
|
+
return getStreamImage(this.event);
|
|
33
|
+
}
|
|
34
|
+
get status() {
|
|
35
|
+
return getStreamStatus(this.event);
|
|
36
|
+
}
|
|
37
|
+
get host() {
|
|
38
|
+
return castUser(getStreamHost(this.event), this.store);
|
|
39
|
+
}
|
|
40
|
+
get participants() {
|
|
41
|
+
return getStreamParticipants(this.event).map((p) => castUser(p, this.store));
|
|
42
|
+
}
|
|
43
|
+
get goalPointer() {
|
|
44
|
+
return getStreamGoalPointer(this.event);
|
|
45
|
+
}
|
|
46
|
+
get streamingURLs() {
|
|
47
|
+
return getStreamStreamingURLs(this.event);
|
|
48
|
+
}
|
|
49
|
+
get streamingVideos() {
|
|
50
|
+
return this.streamingURLs.filter((url) => isVideoURL(url) || isStreamURL(url));
|
|
51
|
+
}
|
|
52
|
+
get streamingAudio() {
|
|
53
|
+
return this.streamingURLs.filter((url) => isAudioURL(url) || isStreamURL(url));
|
|
54
|
+
}
|
|
55
|
+
get recording() {
|
|
56
|
+
return getStreamRecording(this.event);
|
|
57
|
+
}
|
|
58
|
+
get relays() {
|
|
59
|
+
return getStreamRelays(this.event);
|
|
60
|
+
}
|
|
61
|
+
get startTime() {
|
|
62
|
+
return getStreamStartTime(this.event);
|
|
63
|
+
}
|
|
64
|
+
get endTime() {
|
|
65
|
+
return getStreamEndTime(this.event);
|
|
66
|
+
}
|
|
67
|
+
get viewers() {
|
|
68
|
+
return getStreamViewers(this.event);
|
|
69
|
+
}
|
|
70
|
+
get maxViewers() {
|
|
71
|
+
return getStreamMaxViewers(this.event);
|
|
72
|
+
}
|
|
73
|
+
get hashtags() {
|
|
74
|
+
return getStreamHashtags(this.event);
|
|
75
|
+
}
|
|
76
|
+
/** An observable of all zaps on this stream */
|
|
77
|
+
get zaps$() {
|
|
78
|
+
return this.$$ref("zaps$", (store) => store.model(EventZapsModel, this.event).pipe(castTimelineStream(Zap, store)));
|
|
79
|
+
}
|
|
80
|
+
get shares$() {
|
|
81
|
+
return this.$$ref("shares$", (store) => store.model(SharesModel, this.event).pipe(castTimelineStream(Share, store)));
|
|
82
|
+
}
|
|
83
|
+
/** An observable of all chat messages for this stream */
|
|
84
|
+
get chat$() {
|
|
85
|
+
return this.$$ref("chat$", (store) => store.model(StreamChatMessagesModel, this.event).pipe(castTimelineStream(StreamChatMessage, store)));
|
|
86
|
+
}
|
|
87
|
+
/** An observable of the goal event if this stream has a goal */
|
|
88
|
+
get goal$() {
|
|
89
|
+
return this.$$ref("goal$", (store) => {
|
|
90
|
+
const goalPointer = this.goalPointer;
|
|
91
|
+
if (!goalPointer)
|
|
92
|
+
return of(undefined);
|
|
93
|
+
return store.event(goalPointer.id);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** A cast for a stream chat message */
|
|
98
|
+
export class StreamChatMessage extends EventCast {
|
|
99
|
+
constructor(event, store) {
|
|
100
|
+
if (!isValidStreamChatMessage(event))
|
|
101
|
+
throw new Error("Invalid stream chat message");
|
|
102
|
+
super(event, store);
|
|
103
|
+
}
|
|
104
|
+
get stream() {
|
|
105
|
+
return getStreamChatMessageStream(this.event);
|
|
106
|
+
}
|
|
107
|
+
get stream$() {
|
|
108
|
+
return this.$$ref("stream$", (store) => store.replaceable(this.stream).pipe(castEventStream(Stream, store)));
|
|
109
|
+
}
|
|
110
|
+
get zaps$() {
|
|
111
|
+
return this.$$ref("zaps$", (store) => store.model(EventZapsModel, this.event).pipe(castTimelineStream(Zap, store)));
|
|
112
|
+
}
|
|
113
|
+
get reactions$() {
|
|
114
|
+
return this.$$ref("reactions$", (store) => store.model(ReactionsModel, this.event));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NostrEvent, ProfilePointer } from "applesauce-core/helpers";
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { ChainableObservable } from "../observable/chainable.js";
|
|
4
|
+
import { type CastRefEventStore } from "./cast.js";
|
|
5
|
+
/** Cast a nostr event or pointer into a {@link User} */
|
|
6
|
+
export declare function castUser(event: NostrEvent, store: CastRefEventStore): User;
|
|
7
|
+
export declare function castUser(user: string | ProfilePointer, store: CastRefEventStore): User;
|
|
8
|
+
/** A class for a user */
|
|
9
|
+
export declare class User {
|
|
10
|
+
#private;
|
|
11
|
+
pubkey: string;
|
|
12
|
+
/** A global cache of pubkey -> {@link User} */
|
|
13
|
+
static cache: Map<string, User>;
|
|
14
|
+
constructor(user: string | ProfilePointer, store: CastRefEventStore);
|
|
15
|
+
/** Internal method for creating a reference */
|
|
16
|
+
protected $$ref<Return extends unknown>(key: string, builder: (store: CastRefEventStore) => Observable<Return>): ChainableObservable<Return>;
|
|
17
|
+
get npub(): `npub1${string}`;
|
|
18
|
+
get pointer(): ProfilePointer;
|
|
19
|
+
get nprofile(): `nprofile1${string}`;
|
|
20
|
+
replaceable(kind: number, identifier?: string, relays?: string[]): ChainableObservable<NostrEvent | undefined>;
|
|
21
|
+
addressable(kind: number, identifier: string, relays?: string[]): ChainableObservable<NostrEvent | undefined>;
|
|
22
|
+
get profile$(): ChainableObservable<import("./profile.js").Profile | undefined>;
|
|
23
|
+
get contacts$(): ChainableObservable<User[]>;
|
|
24
|
+
get mutes$(): ChainableObservable<import("./mutes.js").Mutes | undefined>;
|
|
25
|
+
get mailboxes$(): ChainableObservable<{
|
|
26
|
+
inboxes: string[];
|
|
27
|
+
outboxes: string[];
|
|
28
|
+
} | undefined>;
|
|
29
|
+
get outboxes$(): ChainableObservable<string[] | undefined>;
|
|
30
|
+
get inboxes$(): ChainableObservable<string[] | undefined>;
|
|
31
|
+
get bookmarks$(): ChainableObservable<import("./bookmarks.js").BookmarksList | undefined>;
|
|
32
|
+
get favoriteRelays$(): ChainableObservable<import("./relay-lists.js").FavoriteRelays | undefined>;
|
|
33
|
+
get searchRelays$(): ChainableObservable<import("./relay-lists.js").SearchRelays | undefined>;
|
|
34
|
+
get blockedRelays$(): ChainableObservable<import("./relay-lists.js").BlockedRelays | undefined>;
|
|
35
|
+
get directMessageRelays$(): ChainableObservable<string[] | undefined>;
|
|
36
|
+
/** Get the latest live stream for the user */
|
|
37
|
+
get live$(): ChainableObservable<import("./stream.js").Stream | undefined>;
|
|
38
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { isEvent, isHexKey, kinds, nprofileEncode, npubEncode, } from "applesauce-core/helpers";
|
|
2
|
+
import { combineLatest, defer, from, map, switchMap, tap } from "rxjs";
|
|
3
|
+
import { FAVORITE_RELAYS_KIND } from "../helpers/relay-list.js";
|
|
4
|
+
import { castEventStream } from "../observable/cast-stream.js";
|
|
5
|
+
import { chainable } from "../observable/chainable.js";
|
|
6
|
+
import { getRelaysFromList } from "../helpers/lists.js";
|
|
7
|
+
export function castUser(user, store) {
|
|
8
|
+
if (isEvent(user)) {
|
|
9
|
+
return castUser(user.pubkey, store);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const pubkey = typeof user === "string" ? user : user.pubkey;
|
|
13
|
+
// Skip creating a new instance if this pubkey has already been cast
|
|
14
|
+
const existing = User.cache.get(pubkey);
|
|
15
|
+
if (existing)
|
|
16
|
+
return existing;
|
|
17
|
+
// Create a new instance and cache it
|
|
18
|
+
const newUser = new User(pubkey, store);
|
|
19
|
+
User.cache.set(pubkey, newUser);
|
|
20
|
+
return newUser;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// IMPORTANT: this class MUST use async import() to import the other classes so that we do not get circular dependency errors
|
|
24
|
+
/** A class for a user */
|
|
25
|
+
export class User {
|
|
26
|
+
pubkey;
|
|
27
|
+
#store;
|
|
28
|
+
/** A cache of the users outboxes for creating a profile pointer relay hints */
|
|
29
|
+
#outboxes;
|
|
30
|
+
/** A global cache of pubkey -> {@link User} */
|
|
31
|
+
static cache = new Map();
|
|
32
|
+
constructor(user, store) {
|
|
33
|
+
if (typeof user === "string" && !isHexKey(user))
|
|
34
|
+
throw new Error("Invalid pubkey for user");
|
|
35
|
+
const pubkey = typeof user === "string" ? user : user.pubkey;
|
|
36
|
+
this.#store = store;
|
|
37
|
+
this.pubkey = pubkey;
|
|
38
|
+
}
|
|
39
|
+
/** A cache of observable references */
|
|
40
|
+
#refs = {};
|
|
41
|
+
/** Internal method for creating a reference */
|
|
42
|
+
$$ref(key, builder) {
|
|
43
|
+
// Return cached observable
|
|
44
|
+
if (this.#refs[key])
|
|
45
|
+
return this.#refs[key];
|
|
46
|
+
// Build a new observable and cache it
|
|
47
|
+
const observable = chainable(builder(this.#store));
|
|
48
|
+
this.#refs[key] = observable;
|
|
49
|
+
return observable;
|
|
50
|
+
}
|
|
51
|
+
// Public getters
|
|
52
|
+
get npub() {
|
|
53
|
+
return npubEncode(this.pubkey);
|
|
54
|
+
}
|
|
55
|
+
get pointer() {
|
|
56
|
+
return {
|
|
57
|
+
pubkey: this.pubkey,
|
|
58
|
+
relays: this.#outboxes?.slice(0, 3) ?? [],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
get nprofile() {
|
|
62
|
+
return nprofileEncode(this.pointer);
|
|
63
|
+
}
|
|
64
|
+
// Request methods
|
|
65
|
+
replaceable(kind, identifier, relays) {
|
|
66
|
+
return chainable(this.#store.replaceable({ kind, pubkey: this.pubkey, identifier, relays }));
|
|
67
|
+
}
|
|
68
|
+
addressable(kind, identifier, relays) {
|
|
69
|
+
return chainable(this.#store.addressable({ kind, pubkey: this.pubkey, identifier, relays }));
|
|
70
|
+
}
|
|
71
|
+
// Observable interfaces
|
|
72
|
+
get profile$() {
|
|
73
|
+
return this.$$ref("profile$", (store) => defer(() => from(import("./profile.js").then((m) => m.Profile))).pipe(switchMap((Profile) => store.replaceable({ kind: kinds.Metadata, pubkey: this.pubkey }).pipe(castEventStream(Profile, store)))));
|
|
74
|
+
}
|
|
75
|
+
get contacts$() {
|
|
76
|
+
return this.$$ref("contacts$", (store) => this.outboxes$.pipe(
|
|
77
|
+
// Fetch the contacts from the outboxes
|
|
78
|
+
switchMap((outboxes) => store.contacts({ pubkey: this.pubkey, relays: outboxes })),
|
|
79
|
+
// Cast to users
|
|
80
|
+
map((arr) => arr.map((p) => castUser(p, this.#store)))));
|
|
81
|
+
}
|
|
82
|
+
get mutes$() {
|
|
83
|
+
return this.$$ref("mutes$", (store) => combineLatest([
|
|
84
|
+
// Import the Mutes class
|
|
85
|
+
defer(() => import("./mutes.js").then((m) => m.Mutes)),
|
|
86
|
+
// Always start without the outboxes
|
|
87
|
+
this.outboxes$,
|
|
88
|
+
]).pipe(
|
|
89
|
+
// Create the mute list event with the outboxes
|
|
90
|
+
switchMap(([Mutes, outboxes]) => store
|
|
91
|
+
.event({ kind: kinds.Mutelist, pubkey: this.pubkey, relays: outboxes })
|
|
92
|
+
.pipe(castEventStream(Mutes, store)))));
|
|
93
|
+
}
|
|
94
|
+
get mailboxes$() {
|
|
95
|
+
return this.$$ref("mailboxes$", (store) => store.mailboxes({ pubkey: this.pubkey }).pipe(
|
|
96
|
+
// Cache the outboxes for creating a profile pointer relay hints
|
|
97
|
+
tap((mailboxes) => (this.#outboxes = mailboxes?.outboxes))));
|
|
98
|
+
}
|
|
99
|
+
get outboxes$() {
|
|
100
|
+
return this.mailboxes$.outboxes;
|
|
101
|
+
}
|
|
102
|
+
get inboxes$() {
|
|
103
|
+
return this.mailboxes$.inboxes;
|
|
104
|
+
}
|
|
105
|
+
get bookmarks$() {
|
|
106
|
+
return this.$$ref("bookmarks$", (store) => combineLatest([
|
|
107
|
+
// Import the BookmarksList class
|
|
108
|
+
defer(() => from(import("./bookmarks.js").then((m) => m.BookmarksList))),
|
|
109
|
+
// Get outboxes and start without them
|
|
110
|
+
this.outboxes$,
|
|
111
|
+
]).pipe(switchMap(([BookmarksList, outboxes]) =>
|
|
112
|
+
// Fetch the bookmarks list event from the outboxes
|
|
113
|
+
store
|
|
114
|
+
.replaceable({ kind: kinds.BookmarkList, pubkey: this.pubkey, relays: outboxes })
|
|
115
|
+
.pipe(castEventStream(BookmarksList, store)))));
|
|
116
|
+
}
|
|
117
|
+
get favoriteRelays$() {
|
|
118
|
+
return this.$$ref("favoriteRelays$", (store) => combineLatest([
|
|
119
|
+
// Import the FavoriteRelays class
|
|
120
|
+
defer(() => from(import("./relay-lists.js").then((m) => m.FavoriteRelays))),
|
|
121
|
+
// Get outboxes and start without them
|
|
122
|
+
this.outboxes$,
|
|
123
|
+
]).pipe(
|
|
124
|
+
// Fetch the favorite relays list event from the outboxes
|
|
125
|
+
switchMap(([FavoriteRelaysList, outboxes]) => store
|
|
126
|
+
.replaceable({ kind: FAVORITE_RELAYS_KIND, pubkey: this.pubkey, relays: outboxes })
|
|
127
|
+
.pipe(castEventStream(FavoriteRelaysList, store)))));
|
|
128
|
+
}
|
|
129
|
+
get searchRelays$() {
|
|
130
|
+
return this.$$ref("searchRelays$", (store) => combineLatest([
|
|
131
|
+
// Import the SearchRelays class
|
|
132
|
+
defer(() => from(import("./relay-lists.js").then((m) => m.SearchRelays))),
|
|
133
|
+
// Get outboxes and start without them
|
|
134
|
+
this.outboxes$,
|
|
135
|
+
]).pipe(
|
|
136
|
+
// Fetch the search relays list event from the outboxes
|
|
137
|
+
switchMap(([SearchRelaysList, outboxes]) => store
|
|
138
|
+
.replaceable({ kind: kinds.SearchRelaysList, pubkey: this.pubkey, relays: outboxes })
|
|
139
|
+
.pipe(castEventStream(SearchRelaysList, store)))));
|
|
140
|
+
}
|
|
141
|
+
get blockedRelays$() {
|
|
142
|
+
return this.$$ref("blockedRelays$", (store) => combineLatest([
|
|
143
|
+
// Import the BlockedRelays class
|
|
144
|
+
defer(() => from(import("./relay-lists.js").then((m) => m.BlockedRelays))),
|
|
145
|
+
// Get outboxes and start without them
|
|
146
|
+
this.outboxes$,
|
|
147
|
+
]).pipe(
|
|
148
|
+
// Fetch the blocked relays list event from the outboxes
|
|
149
|
+
switchMap(([BlockedRelaysList, outboxes]) => store
|
|
150
|
+
.replaceable({ kind: kinds.BlockedRelaysList, pubkey: this.pubkey, relays: outboxes })
|
|
151
|
+
.pipe(castEventStream(BlockedRelaysList, store)))));
|
|
152
|
+
}
|
|
153
|
+
get directMessageRelays$() {
|
|
154
|
+
return this.$$ref("dmRelays$", (store) => this.outboxes$.pipe(
|
|
155
|
+
// Fetch the DM relays list event from the outboxes
|
|
156
|
+
switchMap((outboxes) => store
|
|
157
|
+
.replaceable({ kind: kinds.DirectMessageRelaysList, pubkey: this.pubkey, relays: outboxes })
|
|
158
|
+
.pipe(map((event) => event && getRelaysFromList(event))))));
|
|
159
|
+
}
|
|
160
|
+
/** Get the latest live stream for the user */
|
|
161
|
+
get live$() {
|
|
162
|
+
return this.$$ref("live$", (store) => defer(() => import("./stream.js").then((m) => m.Stream)).pipe(switchMap((Stream) => store
|
|
163
|
+
.timeline([
|
|
164
|
+
{ kinds: [kinds.LiveEvent], "#p": [this.pubkey] },
|
|
165
|
+
{ kinds: [kinds.LiveEvent], authors: [this.pubkey] },
|
|
166
|
+
])
|
|
167
|
+
.pipe(map((events) => events[0]), castEventStream(Stream, store)))));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NostrEvent } from "applesauce-core/helpers";
|
|
2
|
+
import { ZapEvent } from "../helpers/zap.js";
|
|
3
|
+
import { CastRefEventStore, EventCast } from "./cast.js";
|
|
4
|
+
/** Cast a kind 9735 event to a Zap */
|
|
5
|
+
export declare class Zap extends EventCast<ZapEvent> {
|
|
6
|
+
constructor(event: NostrEvent, store: CastRefEventStore);
|
|
7
|
+
get sender(): import("./user.js").User;
|
|
8
|
+
get recipient(): import("./user.js").User;
|
|
9
|
+
get payment(): import("../helpers/bolt11.js").ParsedInvoice;
|
|
10
|
+
get amount(): number;
|
|
11
|
+
get preimage(): string | undefined;
|
|
12
|
+
get request(): import("nostr-tools").Event;
|
|
13
|
+
get addressPointer(): import("nostr-tools/nip19").AddressPointer | null;
|
|
14
|
+
get eventPointer(): import("nostr-tools/nip19").EventPointer | null;
|
|
15
|
+
/** An observable of the zapped event */
|
|
16
|
+
get event$(): import("../observable/chainable.js").ChainableObservable<import("nostr-tools").Event | undefined>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { of } from "rxjs";
|
|
2
|
+
import { getZapAddressPointer, getZapAmount, getZapEventPointer, getZapPayment, getZapPreimage, getZapRecipient, getZapRequest, getZapSender, isValidZap, } from "../helpers/zap.js";
|
|
3
|
+
import { EventCast } from "./cast.js";
|
|
4
|
+
import { castUser } from "./user.js";
|
|
5
|
+
// NOTE: extending BaseCast since there is no need for author$ or comments$
|
|
6
|
+
/** Cast a kind 9735 event to a Zap */
|
|
7
|
+
export class Zap extends EventCast {
|
|
8
|
+
constructor(event, store) {
|
|
9
|
+
if (!isValidZap(event))
|
|
10
|
+
throw new Error("Invalid zap");
|
|
11
|
+
super(event, store);
|
|
12
|
+
}
|
|
13
|
+
get sender() {
|
|
14
|
+
return castUser(getZapSender(this.event), this.store);
|
|
15
|
+
}
|
|
16
|
+
get recipient() {
|
|
17
|
+
return castUser(getZapRecipient(this.event), this.store);
|
|
18
|
+
}
|
|
19
|
+
get payment() {
|
|
20
|
+
return getZapPayment(this.event);
|
|
21
|
+
}
|
|
22
|
+
get amount() {
|
|
23
|
+
return getZapAmount(this.event);
|
|
24
|
+
}
|
|
25
|
+
get preimage() {
|
|
26
|
+
return getZapPreimage(this.event);
|
|
27
|
+
}
|
|
28
|
+
get request() {
|
|
29
|
+
return getZapRequest(this.event);
|
|
30
|
+
}
|
|
31
|
+
get addressPointer() {
|
|
32
|
+
return getZapAddressPointer(this.event);
|
|
33
|
+
}
|
|
34
|
+
get eventPointer() {
|
|
35
|
+
return getZapEventPointer(this.event);
|
|
36
|
+
}
|
|
37
|
+
/** An observable of the zapped event */
|
|
38
|
+
get event$() {
|
|
39
|
+
return this.$$ref("event$", (store) => {
|
|
40
|
+
if (this.addressPointer)
|
|
41
|
+
return store.replaceable(this.addressPointer);
|
|
42
|
+
if (this.eventPointer)
|
|
43
|
+
return store.event(this.eventPointer.id);
|
|
44
|
+
return of(undefined);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|