applesauce-common 0.0.0-next-20251205152544 → 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.
Files changed (107) hide show
  1. package/dist/blueprints/__register__.d.ts +6 -0
  2. package/dist/blueprints/__register__.js +7 -0
  3. package/dist/blueprints/group-mangement.d.ts +25 -0
  4. package/dist/blueprints/group-mangement.js +40 -0
  5. package/dist/blueprints/index.d.ts +1 -0
  6. package/dist/blueprints/index.js +1 -0
  7. package/dist/casts/article.d.ts +17 -0
  8. package/dist/casts/article.js +41 -0
  9. package/dist/casts/bookmarks.d.ts +35 -0
  10. package/dist/casts/bookmarks.js +79 -0
  11. package/dist/casts/cast.d.ts +30 -0
  12. package/dist/casts/cast.js +67 -0
  13. package/dist/casts/comment.d.ts +16 -0
  14. package/dist/casts/comment.js +49 -0
  15. package/dist/casts/index.d.ts +12 -0
  16. package/dist/casts/index.js +12 -0
  17. package/dist/casts/mutes.d.ts +23 -0
  18. package/dist/casts/mutes.js +54 -0
  19. package/dist/casts/note.d.ts +17 -0
  20. package/dist/casts/note.js +46 -0
  21. package/dist/casts/profile.d.ts +16 -0
  22. package/dist/casts/profile.js +40 -0
  23. package/dist/casts/relay-lists.d.ts +33 -0
  24. package/dist/casts/relay-lists.js +72 -0
  25. package/dist/casts/share.d.ts +13 -0
  26. package/dist/casts/share.js +28 -0
  27. package/dist/casts/stream.d.ts +43 -0
  28. package/dist/casts/stream.js +116 -0
  29. package/dist/casts/user.d.ts +38 -0
  30. package/dist/casts/user.js +169 -0
  31. package/dist/casts/zap.d.ts +17 -0
  32. package/dist/casts/zap.js +47 -0
  33. package/dist/helpers/bookmark.d.ts +18 -17
  34. package/dist/helpers/bookmark.js +36 -45
  35. package/dist/helpers/calendar-event.js +12 -5
  36. package/dist/helpers/calendar-rsvp.js +3 -3
  37. package/dist/helpers/calendar.js +4 -1
  38. package/dist/helpers/comment.js +2 -0
  39. package/dist/helpers/encrypted-content-cache.js +23 -25
  40. package/dist/helpers/gift-wrap.js +11 -5
  41. package/dist/helpers/groups.d.ts +118 -6
  42. package/dist/helpers/groups.js +287 -10
  43. package/dist/helpers/highlight.js +4 -2
  44. package/dist/helpers/index.d.ts +1 -1
  45. package/dist/helpers/index.js +1 -1
  46. package/dist/helpers/lists.d.ts +0 -1
  47. package/dist/helpers/lists.js +15 -13
  48. package/dist/helpers/mute.d.ts +14 -11
  49. package/dist/helpers/mute.js +9 -4
  50. package/dist/helpers/reaction.js +11 -7
  51. package/dist/helpers/relay-list.d.ts +14 -0
  52. package/dist/helpers/relay-list.js +18 -0
  53. package/dist/helpers/share.js +3 -3
  54. package/dist/helpers/stream-chat.d.ts +4 -1
  55. package/dist/helpers/stream-chat.js +5 -2
  56. package/dist/helpers/stream.js +12 -6
  57. package/dist/helpers/user-status.js +15 -6
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.js +2 -0
  60. package/dist/models/__register__.d.ts +5 -0
  61. package/dist/models/__register__.js +6 -0
  62. package/dist/models/bookmarks.d.ts +3 -5
  63. package/dist/models/bookmarks.js +2 -10
  64. package/dist/models/calendar.js +5 -2
  65. package/dist/models/comments.js +3 -9
  66. package/dist/models/index.d.ts +4 -0
  67. package/dist/models/index.js +5 -0
  68. package/dist/models/mutes.d.ts +5 -5
  69. package/dist/models/pins.js +1 -1
  70. package/dist/models/reactions.d.ts +1 -1
  71. package/dist/models/reactions.js +3 -13
  72. package/dist/models/relay-lists.d.ts +27 -0
  73. package/dist/models/relay-lists.js +37 -0
  74. package/dist/models/shares.d.ts +3 -0
  75. package/dist/models/shares.js +5 -0
  76. package/dist/models/stream.d.ts +4 -0
  77. package/dist/models/stream.js +6 -0
  78. package/dist/models/thread.js +32 -26
  79. package/dist/models/zaps.d.ts +3 -2
  80. package/dist/models/zaps.js +5 -13
  81. package/dist/observable/cast-stream.d.ts +8 -0
  82. package/dist/observable/cast-stream.js +29 -0
  83. package/dist/observable/chainable.d.ts +50 -0
  84. package/dist/observable/chainable.js +79 -0
  85. package/dist/observable/filter-timeline-by-mutes.d.ts +6 -0
  86. package/dist/observable/filter-timeline-by-mutes.js +7 -0
  87. package/dist/observable/index.d.ts +3 -0
  88. package/dist/observable/index.js +3 -0
  89. package/dist/operations/calendar-rsvp.js +2 -0
  90. package/dist/operations/calendar.js +2 -3
  91. package/dist/operations/client.js +2 -2
  92. package/dist/operations/group.d.ts +14 -1
  93. package/dist/operations/group.js +42 -4
  94. package/dist/operations/highlight.js +21 -5
  95. package/dist/operations/index.d.ts +1 -1
  96. package/dist/operations/index.js +1 -1
  97. package/dist/operations/live-stream.js +10 -4
  98. package/dist/operations/share.js +3 -1
  99. package/dist/operations/stream-chat.d.ts +3 -2
  100. package/dist/operations/stream-chat.js +7 -2
  101. package/dist/operations/tag/bookmarks.d.ts +3 -2
  102. package/dist/operations/tag/bookmarks.js +34 -12
  103. package/dist/register.d.ts +2 -11
  104. package/dist/register.js +2 -11
  105. package/package.json +28 -3
  106. package/dist/helpers/mailboxes.d.ts +0 -7
  107. package/dist/helpers/mailboxes.js +0 -49
@@ -1,9 +1,12 @@
1
+ import { kinds } from "applesauce-core/helpers/event";
1
2
  import { getAddressPointerFromATag } from "applesauce-core/helpers/pointers";
2
3
  import { isATag } from "applesauce-core/helpers/tags";
3
- /** Returns the pointer to the stream chat message stream */
4
+ export function isValidStreamChatMessage(event) {
5
+ return event.kind === kinds.LiveChatMessage && getStreamChatMessageStream(event) !== undefined;
6
+ }
4
7
  export function getStreamChatMessageStream(message) {
5
8
  const tag = message.tags.find(isATag);
6
9
  if (!tag)
7
10
  return undefined;
8
- return getAddressPointerFromATag(tag);
11
+ return getAddressPointerFromATag(tag) ?? undefined;
9
12
  }
@@ -1,7 +1,7 @@
1
1
  import { getTagValue } from "applesauce-core/helpers/event";
2
2
  import { addRelayHintsToPointer, getEventPointerFromETag, getProfilePointerFromPTag, } from "applesauce-core/helpers/pointers";
3
3
  import { mergeRelaySets } from "applesauce-core/helpers/relays";
4
- import { isPTag } from "applesauce-core/helpers/tags";
4
+ import { isPTag, processTags } from "applesauce-core/helpers/tags";
5
5
  import { unixNow } from "applesauce-core/helpers/time";
6
6
  export function getStreamTitle(stream) {
7
7
  return getTagValue(stream, "title");
@@ -25,20 +25,26 @@ export function getStreamHost(stream) {
25
25
  let host = undefined;
26
26
  for (const tag of stream.tags) {
27
27
  if (isPTag(tag) && (!host || (tag[3] && tag[3].toLowerCase() === "host"))) {
28
- host = getProfilePointerFromPTag(tag);
28
+ host = getProfilePointerFromPTag(tag) ?? undefined;
29
29
  }
30
30
  }
31
31
  return host || { pubkey: stream.pubkey };
32
32
  }
33
33
  /** Returns the participants of a stream */
34
34
  export function getStreamParticipants(stream) {
35
- return stream.tags
36
- .filter((t) => isPTag(t) && t[3])
37
- .map((t) => ({ ...getProfilePointerFromPTag(t), role: t[3].toLowerCase() }));
35
+ return processTags(stream.tags, (t) => (isPTag(t) && t[3] ? t : undefined), (t) => {
36
+ const pointer = getProfilePointerFromPTag(t);
37
+ if (!pointer)
38
+ return undefined;
39
+ return { ...pointer, role: t[3].toLowerCase() };
40
+ });
38
41
  }
39
42
  export function getStreamGoalPointer(stream) {
40
43
  const goalTag = stream.tags.find((t) => t[0] === "goal");
41
- return goalTag && addRelayHintsToPointer(getEventPointerFromETag(goalTag), getStreamRelays(stream));
44
+ const pointer = goalTag ? getEventPointerFromETag(goalTag) : undefined;
45
+ if (!pointer)
46
+ return undefined;
47
+ return addRelayHintsToPointer(pointer, getStreamRelays(stream));
42
48
  }
43
49
  /** Gets all the streaming urls for a stream */
44
50
  export function getStreamStreamingURLs(stream) {
@@ -3,14 +3,23 @@ import { getAddressPointerFromATag, getEventPointerFromETag, getProfilePointerFr
3
3
  export const UserStatusPointerSymbol = Symbol.for("user-status-pointer");
4
4
  function getStatusPointer(status) {
5
5
  const pTag = status.tags.find((t) => t[0] === "p" && t[1]);
6
- if (pTag)
7
- return { type: "nprofile", data: getProfilePointerFromPTag(pTag) };
6
+ if (pTag) {
7
+ const pointer = getProfilePointerFromPTag(pTag);
8
+ if (pointer)
9
+ return { type: "nprofile", data: pointer };
10
+ }
8
11
  const eTag = status.tags.find((t) => t[0] === "e" && t[1]);
9
- if (eTag)
10
- return { type: "nevent", data: getEventPointerFromETag(eTag) };
12
+ if (eTag) {
13
+ const pointer = getEventPointerFromETag(eTag);
14
+ if (pointer)
15
+ return { type: "nevent", data: pointer };
16
+ }
11
17
  const aTag = status.tags.find((t) => t[0] === "a" && t[1]);
12
- if (aTag)
13
- return { type: "naddr", data: getAddressPointerFromATag(aTag) };
18
+ if (aTag) {
19
+ const pointer = getAddressPointerFromATag(aTag);
20
+ if (pointer)
21
+ return { type: "naddr", data: pointer };
22
+ }
14
23
  const rTag = status.tags.find((t) => t[0] === "r" && t[1]);
15
24
  if (rTag)
16
25
  return { type: "url", data: rTag[1] };
package/dist/index.d.ts CHANGED
@@ -2,4 +2,6 @@ export * as Helpers from "./helpers/index.js";
2
2
  export * as Models from "./models/index.js";
3
3
  export * as Operations from "./operations/index.js";
4
4
  export * as Blueprints from "./blueprints/index.js";
5
+ export * as Observable from "./observable/index.js";
6
+ export * as Casts from "./casts/index.js";
5
7
  import "./register.js";
package/dist/index.js CHANGED
@@ -2,5 +2,7 @@ export * as Helpers from "./helpers/index.js";
2
2
  export * as Models from "./models/index.js";
3
3
  export * as Operations from "./operations/index.js";
4
4
  export * as Blueprints from "./blueprints/index.js";
5
+ export * as Observable from "./observable/index.js";
6
+ export * as Casts from "./casts/index.js";
5
7
  // Register the common models and blueprints with the event store and event factory
6
8
  import "./register.js";
@@ -0,0 +1,5 @@
1
+ import "./blossom.js";
2
+ import "./mutes.js";
3
+ import "./reactions.js";
4
+ import "./comments.js";
5
+ import "./thread.js";
@@ -0,0 +1,6 @@
1
+ // Import models that should register with the event store
2
+ import "./blossom.js";
3
+ import "./mutes.js";
4
+ import "./reactions.js";
5
+ import "./comments.js";
6
+ import "./thread.js";
@@ -1,8 +1,6 @@
1
1
  import { Model } from "applesauce-core/event-store";
2
- import { Bookmarks } from "../helpers/bookmark.js";
2
+ import { BookmarkPointer } from "../helpers/bookmark.js";
3
3
  /** A model that returns all the bookmarks of a user */
4
- export declare function UserBookmarkModel(pubkey: string): Model<Bookmarks | undefined>;
5
- /** A model that returns all the public bookmarks of a user */
6
- export declare function UserPublicBookmarkModel(pubkey: string): Model<Bookmarks | undefined>;
4
+ export declare function UserBookmarkModel(pubkey: string): Model<BookmarkPointer[] | undefined>;
7
5
  /** A model that returns all the hidden bookmarks of a user */
8
- export declare function UserHiddenBookmarkModel(pubkey: string): Model<Bookmarks | null | undefined>;
6
+ export declare function UserHiddenBookmarkModel(pubkey: string): Model<BookmarkPointer[] | null | undefined>;
@@ -1,18 +1,10 @@
1
1
  import { kinds } from "applesauce-core/helpers/event";
2
2
  import { watchEventUpdates } from "applesauce-core/observable";
3
3
  import { map } from "rxjs/operators";
4
- import { getBookmarks, getHiddenBookmarks, getPublicBookmarks } from "../helpers/bookmark.js";
4
+ import { getBookmarks, getHiddenBookmarks } from "../helpers/bookmark.js";
5
5
  /** A model that returns all the bookmarks of a user */
6
6
  export function UserBookmarkModel(pubkey) {
7
- return (events) => events.replaceable(kinds.Mutelist, pubkey).pipe(
8
- // listen for event updates (hidden tags unlocked)
9
- watchEventUpdates(events),
10
- // Get all bookmarks
11
- map((event) => event && getBookmarks(event)));
12
- }
13
- /** A model that returns all the public bookmarks of a user */
14
- export function UserPublicBookmarkModel(pubkey) {
15
- return (events) => events.replaceable(kinds.Mutelist, pubkey).pipe(map((event) => event && getPublicBookmarks(event)));
7
+ return (events) => events.replaceable(kinds.BookmarkList, pubkey).pipe(map((event) => event && getBookmarks(event)));
16
8
  }
17
9
  /** A model that returns all the hidden bookmarks of a user */
18
10
  export function UserHiddenBookmarkModel(pubkey) {
@@ -1,6 +1,6 @@
1
1
  import { getReplaceableAddress } from "applesauce-core/helpers/event";
2
2
  import { defined } from "applesauce-core/observable";
3
- import { combineLatest } from "rxjs";
3
+ import { combineLatest, EMPTY } from "rxjs";
4
4
  import { CALENDAR_EVENT_RSVP_KIND } from "../helpers/calendar-rsvp.js";
5
5
  import { getCalendarAddressPointers } from "../helpers/calendar.js";
6
6
  /** A model that gets all the events for a calendar */
@@ -10,6 +10,9 @@ export function CalendarEventsModel(calendar) {
10
10
  /** A model that gets all the RSVPs for a calendar event */
11
11
  export function CalendarEventRSVPsModel(event) {
12
12
  return (events) => {
13
- return events.timeline({ kinds: [CALENDAR_EVENT_RSVP_KIND], "#a": [getReplaceableAddress(event)] });
13
+ const address = getReplaceableAddress(event);
14
+ if (!address)
15
+ return EMPTY;
16
+ return events.timeline({ kinds: [CALENDAR_EVENT_RSVP_KIND], "#a": [address] });
14
17
  };
15
18
  }
@@ -1,15 +1,9 @@
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
1
  import { EventModels } from "applesauce-core/event-store";
2
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
3
+ import { COMMENT_KIND } from "../helpers/comment.js";
5
4
  /** A model that returns all NIP-22 comment replies for the event */
6
5
  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
- };
6
+ return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [COMMENT_KIND] }, parent));
13
7
  }
14
8
  // Register this model with EventModels
15
9
  EventModels.prototype.comments = function (event) {
@@ -12,4 +12,8 @@ export * from "./user-status.js";
12
12
  export * from "./wrapped-messages.js";
13
13
  export * from "./zaps.js";
14
14
  export * from "./gift-wrap.js";
15
+ export * from "./relay-lists.js";
16
+ export * from "./stream.js";
17
+ export * from "./shares.js";
18
+ export * from "applesauce-core/models";
15
19
  import "../register.js";
@@ -12,5 +12,10 @@ export * from "./user-status.js";
12
12
  export * from "./wrapped-messages.js";
13
13
  export * from "./zaps.js";
14
14
  export * from "./gift-wrap.js";
15
+ export * from "./relay-lists.js";
16
+ export * from "./stream.js";
17
+ export * from "./shares.js";
18
+ // Export all models from core
19
+ export * from "applesauce-core/models";
15
20
  // Register the common models with the event store
16
21
  import "../register.js";
@@ -1,16 +1,16 @@
1
1
  import { Model } from "applesauce-core/event-store";
2
2
  import { ProfilePointer } from "applesauce-core/helpers/pointers";
3
3
  import { type Observable } from "rxjs";
4
- import { Mutes } from "../helpers/mute.js";
4
+ import { MutedThings } from "../helpers/mute.js";
5
5
  /** A model that returns all a users muted things */
6
- export declare function MuteModel(user: string | ProfilePointer): Model<Mutes | undefined>;
6
+ export declare function MuteModel(user: string | ProfilePointer): Model<MutedThings | undefined>;
7
7
  /** A model that returns all a users public muted things */
8
- export declare function PublicMuteModel(pubkey: string): Model<Mutes | undefined>;
8
+ export declare function PublicMuteModel(pubkey: string): Model<MutedThings | undefined>;
9
9
  /** A model that returns all a users hidden muted things */
10
- export declare function HiddenMuteModel(pubkey: string): Model<Mutes | null | undefined>;
10
+ export declare function HiddenMuteModel(pubkey: string): Model<MutedThings | null | undefined>;
11
11
  declare module "applesauce-core/event-store" {
12
12
  interface EventModels {
13
13
  /** Subscribe to a users mutes */
14
- mutes(user: string | ProfilePointer): Observable<Mutes | undefined>;
14
+ mutes(user: string | ProfilePointer): Observable<MutedThings | undefined>;
15
15
  }
16
16
  }
@@ -6,5 +6,5 @@ import { map } from "rxjs/operators";
6
6
  export function UserPinnedModel(pubkey) {
7
7
  return (events) => events
8
8
  .replaceable(kinds.Pinlist, pubkey)
9
- .pipe(map((event) => event && processTags(event.tags.filter(isETag), getEventPointerFromETag)));
9
+ .pipe(map((event) => event && processTags(event.tags.filter(isETag), (t) => getEventPointerFromETag(t) ?? undefined)));
10
10
  }
@@ -1,5 +1,5 @@
1
- import { NostrEvent } from "applesauce-core/helpers/event";
2
1
  import { Model } from "applesauce-core/event-store";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
3
  import { type Observable } from "rxjs";
4
4
  /** A model that returns all reactions to an event (supports replaceable events) */
5
5
  export declare function ReactionsModel(event: NostrEvent): Model<NostrEvent[]>;
@@ -1,19 +1,9 @@
1
- import { getEventUID, isReplaceable, kinds } from "applesauce-core/helpers/event";
2
- // Import EventModels as a value (class) to modify its prototype
3
1
  import { EventModels } from "applesauce-core/event-store";
2
+ import { kinds } from "applesauce-core/helpers/event";
3
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
4
4
  /** A model that returns all reactions to an event (supports replaceable events) */
5
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
- ]);
6
+ return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [kinds.Reaction] }, event));
17
7
  }
18
8
  // Register this model with EventModels
19
9
  EventModels.prototype.reactions = function (event) {
@@ -0,0 +1,27 @@
1
+ import { Model } from "applesauce-core/event-store";
2
+ import { AddressPointer } from "applesauce-core/helpers/pointers";
3
+ import { ReadListTags } from "../helpers/lists.js";
4
+ /**
5
+ * A model that returns all favorite relays for a pubkey
6
+ * @param pubkey - The pubkey to get the favorite relays for
7
+ * @param type - Which types of tags to read
8
+ */
9
+ export declare function FavoriteRelaysModel(pubkey: string, type?: ReadListTags): Model<string[] | undefined>;
10
+ /**
11
+ * A model that returns all favorite relay sets for a pubkey
12
+ * @param pubkey - The pubkey to get the favorite relay sets for
13
+ * @param type - Which types of tags to read
14
+ */
15
+ export declare function FavoriteRelaySetsModel(pubkey: string, type?: ReadListTags): Model<AddressPointer[] | undefined>;
16
+ /**
17
+ * A model that returns all search relays for a pubkey
18
+ * @param pubkey - The pubkey to get the search relays for
19
+ * @param type - Which types of tags to read
20
+ */
21
+ export declare function SearchRelaysModel(pubkey: string, type?: ReadListTags): Model<string[] | undefined>;
22
+ /**
23
+ * A model that returns all blocked relays for a pubkey
24
+ * @param pubkey - The pubkey to get the blocked relays for
25
+ * @param type - Which types of tags to read
26
+ */
27
+ export declare function BlockedRelaysModel(pubkey: string, type?: ReadListTags): Model<string[] | undefined>;
@@ -0,0 +1,37 @@
1
+ import { kinds } from "applesauce-core/helpers/event";
2
+ import { watchEventUpdates } from "applesauce-core/observable";
3
+ import { identity, map } from "rxjs";
4
+ import { getAddressPointersFromList, getRelaysFromList } from "../helpers/lists.js";
5
+ import { FAVORITE_RELAYS_KIND } from "../helpers/relay-list.js";
6
+ /**
7
+ * A model that returns all favorite relays for a pubkey
8
+ * @param pubkey - The pubkey to get the favorite relays for
9
+ * @param type - Which types of tags to read
10
+ */
11
+ export function FavoriteRelaysModel(pubkey, type) {
12
+ return (events) => events.replaceable(FAVORITE_RELAYS_KIND, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
13
+ }
14
+ /**
15
+ * A model that returns all favorite relay sets for a pubkey
16
+ * @param pubkey - The pubkey to get the favorite relay sets for
17
+ * @param type - Which types of tags to read
18
+ */
19
+ export function FavoriteRelaySetsModel(pubkey, type) {
20
+ return (events) => events.replaceable(FAVORITE_RELAYS_KIND, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getAddressPointersFromList(e, type)));
21
+ }
22
+ /**
23
+ * A model that returns all search relays for a pubkey
24
+ * @param pubkey - The pubkey to get the search relays for
25
+ * @param type - Which types of tags to read
26
+ */
27
+ export function SearchRelaysModel(pubkey, type) {
28
+ return (events) => events.replaceable(kinds.SearchRelaysList, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
29
+ }
30
+ /**
31
+ * A model that returns all blocked relays for a pubkey
32
+ * @param pubkey - The pubkey to get the blocked relays for
33
+ * @param type - Which types of tags to read
34
+ */
35
+ export function BlockedRelaysModel(pubkey, type) {
36
+ return (events) => events.replaceable(kinds.BlockedRelaysList, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
37
+ }
@@ -0,0 +1,3 @@
1
+ import { Model } from "applesauce-core/event-store";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ export declare function SharesModel(event: NostrEvent): Model<NostrEvent[]>;
@@ -0,0 +1,5 @@
1
+ import { kinds } from "applesauce-core/helpers/event";
2
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
3
+ export function SharesModel(event) {
4
+ return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [kinds.Repost, kinds.GenericRepost] }, event));
5
+ }
@@ -0,0 +1,4 @@
1
+ import { Model } from "applesauce-core/event-store";
2
+ import { AddressPointer, NostrEvent } from "applesauce-core/helpers";
3
+ /** A model that returns all chat messages for a stream */
4
+ export declare function StreamChatMessagesModel(stream: AddressPointer | NostrEvent): Model<NostrEvent[]>;
@@ -0,0 +1,6 @@
1
+ import { kinds } from "applesauce-core/helpers/event";
2
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
3
+ /** A model that returns all chat messages for a stream */
4
+ export function StreamChatMessagesModel(stream) {
5
+ return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [kinds.LiveChatMessage] }, stream));
6
+ }
@@ -1,12 +1,10 @@
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
1
  import { EventModels } from "applesauce-core/event-store";
2
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers";
3
+ import { getEventUID, kinds } from "applesauce-core/helpers/event";
4
+ import { eventMatchesPointer, getReplaceableAddressFromPointer, isAddressPointer, } from "applesauce-core/helpers/pointers";
5
+ import { map } from "rxjs/operators";
6
+ import { COMMENT_KIND, getCommentReplyPointer } from "../helpers/comment.js";
7
+ import { getNip10References } from "../helpers/threading.js";
10
8
  const defaultOptions = {
11
9
  kinds: [kinds.ShortTextNote],
12
10
  };
@@ -19,7 +17,7 @@ export function ThreadModel(root, opts) {
19
17
  const rootFilter = {};
20
18
  const replyFilter = { kinds };
21
19
  if (isAddressPointer(root)) {
22
- rootUID = getCoordinateFromAddressPointer(root);
20
+ rootUID = getReplaceableAddressFromPointer(root);
23
21
  rootFilter.kinds = [root.kind];
24
22
  rootFilter.authors = [root.pubkey];
25
23
  rootFilter["#d"] = [root.identifier];
@@ -45,7 +43,7 @@ export function ThreadModel(root, opts) {
45
43
  }
46
44
  // add item to parent
47
45
  if (refs.reply?.e || refs.reply?.a) {
48
- let uid = refs.reply.e ? refs.reply.e.id : getCoordinateFromAddressPointer(refs.reply.a);
46
+ let uid = refs.reply.e ? refs.reply.e.id : getReplaceableAddressFromPointer(refs.reply.a);
49
47
  item.parent = items.get(uid);
50
48
  if (item.parent) {
51
49
  item.parent.replies.add(item);
@@ -69,22 +67,30 @@ export function ThreadModel(root, opts) {
69
67
  /** A model that gets all legacy and NIP-10, and NIP-22 replies for an event */
70
68
  export function RepliesModel(event, overrideKinds) {
71
69
  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
- }));
70
+ const filter = { kinds: overrideKinds || event.kind === 1 ? [1, COMMENT_KIND] : [COMMENT_KIND] };
71
+ return events.timeline(buildCommonEventRelationFilters(filter, event)).pipe(map((events) =>
72
+ // Filter for direct replies
73
+ events.filter((reply) => {
74
+ if (reply.kind === kinds.ShortTextNote) {
75
+ // Check if a NIP-10 reply is a direct reply to this event
76
+ const refs = getNip10References(reply);
77
+ const pointer = refs.reply?.a || refs.reply?.e;
78
+ if (!pointer)
79
+ return false;
80
+ return eventMatchesPointer(event, pointer);
81
+ }
82
+ else if (reply.kind === COMMENT_KIND) {
83
+ // Check if a NIP-22 reply is a direct reply to this event
84
+ const pointer = getCommentReplyPointer(reply);
85
+ if (!pointer)
86
+ return false;
87
+ if (pointer.type === "address")
88
+ return eventMatchesPointer(event, pointer);
89
+ else if (pointer.type === "event")
90
+ return pointer.id === event.id;
91
+ }
92
+ return false;
93
+ })));
88
94
  };
89
95
  }
90
96
  // Register this model with EventModels
@@ -1,8 +1,9 @@
1
1
  import { Model } from "applesauce-core/event-store";
2
- import { KnownEvent, kinds } from "applesauce-core/helpers/event";
2
+ import { NostrEvent } from "applesauce-core/helpers";
3
+ import { kinds, KnownEvent } from "applesauce-core/helpers/event";
3
4
  import { AddressPointer, EventPointer } from "applesauce-core/helpers/pointers";
4
5
  /** A model that gets all zap events for an event */
5
- export declare function EventZapsModel(id: string | EventPointer | AddressPointer): Model<KnownEvent<kinds.Zap>[]>;
6
+ export declare function EventZapsModel(pointer: string | EventPointer | AddressPointer | NostrEvent): Model<KnownEvent<kinds.Zap>[]>;
6
7
  /** A model that returns all zaps sent by a user */
7
8
  export declare function SentZapsModel(pubkey: string): Model<KnownEvent<kinds.Zap>[]>;
8
9
  /** A model that returns all zaps received by a user */
@@ -1,20 +1,12 @@
1
1
  import { kinds } from "applesauce-core/helpers/event";
2
- import { getCoordinateFromAddressPointer, isAddressPointer, } from "applesauce-core/helpers/pointers";
2
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
3
3
  import { map } from "rxjs";
4
4
  import { isValidZap } from "../helpers/zap.js";
5
5
  /** A model that gets all zap events for an event */
6
- export function EventZapsModel(id) {
7
- return (events) => {
8
- if (isAddressPointer(id)) {
9
- return events
10
- .timeline([{ kinds: [kinds.Zap], "#a": [getCoordinateFromAddressPointer(id)] }])
11
- .pipe(map((events) => events.filter(isValidZap)));
12
- }
13
- else {
14
- id = typeof id === "string" ? id : id.id;
15
- return events.timeline([{ kinds: [kinds.Zap], "#e": [id] }]).pipe(map((events) => events.filter(isValidZap)));
16
- }
17
- };
6
+ export function EventZapsModel(pointer) {
7
+ return (events) => events
8
+ .timeline(buildCommonEventRelationFilters({ kinds: [kinds.Zap] }, pointer))
9
+ .pipe(map((events) => events.filter(isValidZap)));
18
10
  }
19
11
  /** A model that returns all zaps sent by a user */
20
12
  export function SentZapsModel(pubkey) {
@@ -0,0 +1,8 @@
1
+ import type { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { OperatorFunction } from "rxjs";
3
+ import type { CastConstructor, CastRefEventStore } from "../casts/cast.js";
4
+ import { EventCast } from "../casts/cast.js";
5
+ /** Casts an event to a specific type */
6
+ export declare function castEventStream<C extends EventCast>(cls: CastConstructor<C>, store?: CastRefEventStore): OperatorFunction<NostrEvent | undefined, C | undefined>;
7
+ /** Casts and array of events to an array of casted events and filters out undefined values */
8
+ export declare function castTimelineStream<C extends EventCast>(cls: CastConstructor<C>, store?: CastRefEventStore): OperatorFunction<NostrEvent[], C[]>;
@@ -0,0 +1,29 @@
1
+ import { defined } from "applesauce-core/observable/defined";
2
+ import { map } from "rxjs";
3
+ import { castEvent } from "../casts/cast.js";
4
+ /** Casts an event to a specific type */
5
+ export function castEventStream(cls, store) {
6
+ return (source) => source.pipe(map((event) => {
7
+ if (!event)
8
+ return undefined;
9
+ try {
10
+ return castEvent(event, cls, store);
11
+ }
12
+ catch { }
13
+ return undefined;
14
+ }));
15
+ }
16
+ /** Casts and array of events to an array of casted events and filters out undefined values */
17
+ export function castTimelineStream(cls, store) {
18
+ return (source) => source.pipe(map((events) => {
19
+ const castedEvents = [];
20
+ for (const event of events) {
21
+ try {
22
+ const casted = castEvent(event, cls, store);
23
+ castedEvents.push(casted);
24
+ }
25
+ catch { }
26
+ }
27
+ return castedEvents;
28
+ }), defined());
29
+ }
@@ -0,0 +1,50 @@
1
+ import { Observable } from "rxjs";
2
+ /**
3
+ * Wraps an Observable in a Proxy that enables property chaining.
4
+ * When accessing a property ending with `$`, it uses switchMap to chain
5
+ * to that property's observable value.
6
+ * When accessing a non-observable property, it returns an Observable of that property's value.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const author$ = chainable(note.author$);
11
+ * const outboxes$ = author$.outboxes$; // Observable<string[] | undefined>
12
+ * const displayName$ = author$.displayName; // Observable<string | undefined>
13
+ * ```
14
+ */
15
+ export declare function chainable<T>(observable: Observable<T>): ChainableObservable<T>;
16
+ /**
17
+ * Helper type to extract nullable parts (undefined/null) from a type
18
+ */
19
+ type NullableParts<T> = Extract<T, undefined | null>;
20
+ /**
21
+ * Helper type to get the property type, preserving nullable parts from the parent type
22
+ */
23
+ type PropChain<T, K extends keyof NonNullable<T>> = NonNullable<T>[K] | NullableParts<T>;
24
+ /**
25
+ * A chainable Observable type that allows property chaining.
26
+ * This type maps all properties to chainable observables:
27
+ * - Properties ending with $: extracts inner type from Observable<U> → ChainableObservable<U>
28
+ * - Other properties: uses property type directly → ChainableObservable<PropertyType>
29
+ *
30
+ * Note: TypeScript has limitations inferring through Proxy types. For better
31
+ * type inference, you may need to explicitly type the result:
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const inboxes$: Observable<string[] | undefined> = note?.author$.inboxes$;
36
+ * const displayName$: Observable<string | undefined> = note?.author$.displayName;
37
+ * const inboxes = useObservableMemo(() => inboxes$, [note]);
38
+ * ```
39
+ */
40
+ export type ChainableObservable<T> = Observable<T> & Omit<{
41
+ [K in keyof NonNullable<T> as K extends string ? K : never]: K extends `${infer _}$` ? NonNullable<T>[K] extends Observable<infer U> ? ChainableObservable<U | NullableParts<T>> : never : ChainableObservable<PropChain<T, K>>;
42
+ }, "$first" | "$last"> & {
43
+ /** Returns a promise that resolves with the first value or rejects with a timeout error */
44
+ $first(first?: number): Promise<NonNullable<T>>;
45
+ $first<V>(first?: number, fallback?: V): Promise<NonNullable<T> | V>;
46
+ /** Returns a promise that resolves with the last value or rejects with a timeout error */
47
+ $last(max?: number): Promise<NonNullable<T>>;
48
+ $last<V>(max?: number, fallback?: V): Promise<NonNullable<T> | V>;
49
+ };
50
+ export {};