applesauce-common 0.0.0-next-20251203172109 → 0.0.0-next-20251209200210

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 (47) hide show
  1. package/dist/helpers/bookmark.js +8 -4
  2. package/dist/helpers/calendar-event.js +12 -5
  3. package/dist/helpers/calendar-rsvp.js +3 -3
  4. package/dist/helpers/calendar.js +4 -1
  5. package/dist/helpers/comment.js +2 -0
  6. package/dist/helpers/groups.d.ts +7 -0
  7. package/dist/helpers/groups.js +22 -2
  8. package/dist/helpers/highlight.js +4 -2
  9. package/dist/helpers/lists.js +12 -9
  10. package/dist/helpers/reaction.js +11 -7
  11. package/dist/helpers/share.js +3 -3
  12. package/dist/helpers/stream-chat.js +1 -1
  13. package/dist/helpers/stream.js +12 -6
  14. package/dist/helpers/user-status.js +15 -6
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +1 -0
  17. package/dist/models/calendar.js +5 -2
  18. package/dist/models/comments.js +3 -9
  19. package/dist/models/index.d.ts +2 -0
  20. package/dist/models/index.js +2 -0
  21. package/dist/models/pins.js +1 -1
  22. package/dist/models/reactions.d.ts +1 -1
  23. package/dist/models/reactions.js +3 -13
  24. package/dist/models/relays.d.ts +27 -0
  25. package/dist/models/relays.js +36 -0
  26. package/dist/models/stream.d.ts +4 -0
  27. package/dist/models/stream.js +6 -0
  28. package/dist/models/thread.js +3 -3
  29. package/dist/models/zaps.d.ts +3 -2
  30. package/dist/models/zaps.js +5 -13
  31. package/dist/observable/filter-timeline-by-mutes.d.ts +6 -0
  32. package/dist/observable/filter-timeline-by-mutes.js +7 -0
  33. package/dist/observable/index.d.ts +1 -0
  34. package/dist/observable/index.js +1 -0
  35. package/dist/operations/calendar-rsvp.js +2 -0
  36. package/dist/operations/calendar.js +2 -3
  37. package/dist/operations/client.js +2 -2
  38. package/dist/operations/group.js +1 -1
  39. package/dist/operations/highlight.js +21 -5
  40. package/dist/operations/live-stream.js +10 -4
  41. package/dist/operations/share.js +3 -1
  42. package/dist/operations/stream-chat.d.ts +3 -2
  43. package/dist/operations/stream-chat.js +7 -2
  44. package/dist/operations/tag/bookmarks.js +9 -7
  45. package/package.json +18 -3
  46. package/dist/helpers/groups-helper.d.ts +0 -6
  47. package/dist/helpers/groups-helper.js +0 -9
@@ -1,16 +1,20 @@
1
1
  import { getOrComputeCachedValue, notifyEventUpdate } from "applesauce-core/helpers";
2
2
  import { kinds } from "applesauce-core/helpers/event";
3
3
  import { getHiddenTags, isHiddenTagsUnlocked, unlockHiddenTags } from "applesauce-core/helpers/hidden-tags";
4
- import { getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag, mergeAddressPointers, mergeEventPointers, } from "applesauce-core/helpers/pointers";
4
+ import { getAddressPointerFromATag, getReplaceableAddressFromPointer, getEventPointerFromETag, mergeAddressPointers, mergeEventPointers, } from "applesauce-core/helpers/pointers";
5
5
  export const BookmarkPublicSymbol = Symbol.for("bookmark-public");
6
6
  export const BookmarkHiddenSymbol = Symbol.for("bookmark-hidden");
7
7
  /** Parses an array of tags into a {@link Bookmarks} object */
8
8
  export function parseBookmarkTags(tags) {
9
- const notes = tags.filter((t) => t[0] === "e" && t[1]).map(getEventPointerFromETag);
9
+ const notes = tags
10
+ .filter((t) => t[0] === "e" && t[1])
11
+ .map(getEventPointerFromETag)
12
+ .filter((pointer) => pointer !== null);
10
13
  const articles = tags
11
14
  .filter((t) => t[0] === "a" && t[1])
12
15
  .map(getAddressPointerFromATag)
13
- .filter((addr) => addr.kind === kinds.LongFormArticle);
16
+ .filter((pointer) => pointer !== null)
17
+ .filter((pointer) => pointer.kind === kinds.LongFormArticle);
14
18
  const hashtags = tags.filter((t) => t[0] === "t" && t[1]).map((t) => t[1]);
15
19
  const urls = tags.filter((t) => t[0] === "r" && t[1]).map((t) => t[1]);
16
20
  return { notes, articles, hashtags, urls };
@@ -32,7 +36,7 @@ export function mergeBookmarks(...bookmarks) {
32
36
  notes.set(note.id, note);
33
37
  }
34
38
  for (const article of bookmark.articles) {
35
- const coord = getCoordinateFromAddressPointer(article);
39
+ const coord = getReplaceableAddressFromPointer(article);
36
40
  const existing = articles.get(coord);
37
41
  if (existing)
38
42
  articles.set(coord, mergeAddressPointers(existing, article));
@@ -86,11 +86,18 @@ export function getCalendarEventParticipants(event) {
86
86
  if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
87
87
  throw new Error("Event is not a date-based or time-based calendar event");
88
88
  return getOrComputeCachedValue(event, CalendarEventParticipantsSymbol, () => {
89
- return event.tags.filter(isPTag).map((tag) => ({
90
- ...getProfilePointerFromPTag(tag),
91
- // Third index of tag is optional "role"
92
- role: tag[3] || undefined,
93
- }));
89
+ return event.tags
90
+ .filter(isPTag)
91
+ .map((tag) => {
92
+ const pointer = getProfilePointerFromPTag(tag);
93
+ if (!pointer)
94
+ return undefined;
95
+ return {
96
+ ...pointer,
97
+ role: tag[3] || undefined,
98
+ };
99
+ })
100
+ .filter((p) => p !== undefined);
94
101
  });
95
102
  }
96
103
  /** Gets all hashtags from a calendar event */
@@ -20,19 +20,19 @@ export function getRSVPAddressPointer(event) {
20
20
  const tag = event.tags.find(isATag);
21
21
  if (!tag)
22
22
  return undefined;
23
- return getAddressPointerFromATag(tag);
23
+ return getAddressPointerFromATag(tag) ?? undefined;
24
24
  }
25
25
  /** Gets the referenced calendar event pointer that the RSVP is responding to */
26
26
  export function getRSVPEventPointer(event) {
27
27
  const tag = event.tags.find(isETag);
28
28
  if (!tag)
29
29
  return undefined;
30
- return getEventPointerFromETag(tag);
30
+ return getEventPointerFromETag(tag) ?? undefined;
31
31
  }
32
32
  /** Gets the profile pointer that the RSVP is responding to */
33
33
  export function getRSVPProfilePointer(event) {
34
34
  const tag = event.tags.find(isPTag);
35
35
  if (!tag)
36
36
  return undefined;
37
- return getProfilePointerFromPTag(tag);
37
+ return getProfilePointerFromPTag(tag) ?? undefined;
38
38
  }
@@ -7,5 +7,8 @@ export function getCalendarTitle(event) {
7
7
  }
8
8
  /** Gets the address pointers to all the events on the calendar */
9
9
  export function getCalendarAddressPointers(event) {
10
- return event.tags.filter(isATag).map(getAddressPointerFromATag);
10
+ return event.tags
11
+ .filter(isATag)
12
+ .map(getAddressPointerFromATag)
13
+ .filter((p) => p !== null);
11
14
  }
@@ -38,6 +38,8 @@ export function getCommentAddressPointer(tags, root = false) {
38
38
  if (!kind)
39
39
  return null;
40
40
  const addressPointer = getAddressPointerFromATag(aTag);
41
+ if (!addressPointer)
42
+ return null;
41
43
  const pointer = {
42
44
  type: "address",
43
45
  id: eTag?.[1],
@@ -1,4 +1,5 @@
1
1
  import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { NameValueTag } from "applesauce-core/helpers/tags";
2
3
  export declare const GROUPS_LIST_KIND = 10009;
3
4
  export declare const GROUP_MESSAGE_KIND = 9;
4
5
  /** NIP-29 group pointer */
@@ -24,3 +25,9 @@ export declare function getGroupPointerFromGroupTag(tag: string[]): GroupPointer
24
25
  export declare function getPublicGroups(bookmark: NostrEvent): GroupPointer[];
25
26
  /** Returns all the hidden groups from a k:10009 list */
26
27
  export declare function getHiddenGroups(bookmark: NostrEvent): GroupPointer[] | undefined;
28
+ /** Gets a {@link GroupPointer} from a kind 39000 group metadata event */
29
+ export declare function getGroupPointerFromMetadata(event: NostrEvent, relay: string): GroupPointer | undefined;
30
+ /** Creates a "h" tag for chat messages from a {@link GroupPointer} */
31
+ export declare function createGroupHTagFromGroupPointer(group: GroupPointer): NameValueTag;
32
+ /** Creates a "group" tag from a {@link GroupPointer} */
33
+ export declare function createGroupTagFromGroupPointer(group: GroupPointer): NameValueTag;
@@ -1,7 +1,8 @@
1
1
  import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
2
+ import { getReplaceableIdentifier, getTagValue } from "applesauce-core/helpers/event";
2
3
  import { getHiddenTags } from "applesauce-core/helpers/hidden-tags";
3
- import { processTags } from "applesauce-core/helpers/tags";
4
- import { normalizeURL } from "applesauce-core/helpers/url";
4
+ import { fillAndTrimTag, processTags } from "applesauce-core/helpers/tags";
5
+ import { ensureWebSocketURL, normalizeURL } from "applesauce-core/helpers/url";
5
6
  export const GROUPS_LIST_KIND = 10009;
6
7
  export const GROUP_MESSAGE_KIND = 9;
7
8
  /** decodes a group identifier into a group pointer object */
@@ -47,3 +48,22 @@ export function getHiddenGroups(bookmark) {
47
48
  processTags(bookmark.tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag));
48
49
  });
49
50
  }
51
+ /** Gets a {@link GroupPointer} from a kind 39000 group metadata event */
52
+ export function getGroupPointerFromMetadata(event, relay) {
53
+ // Use the "d" tag for the group ID and the provided relay
54
+ const groupId = getReplaceableIdentifier(event) || "_";
55
+ const name = getTagValue(event, "name");
56
+ return {
57
+ id: groupId,
58
+ relay: relay,
59
+ name: name,
60
+ };
61
+ }
62
+ /** Creates a "h" tag for chat messages from a {@link GroupPointer} */
63
+ export function createGroupHTagFromGroupPointer(group) {
64
+ return fillAndTrimTag(["h", group.id, ensureWebSocketURL(group.relay)]);
65
+ }
66
+ /** Creates a "group" tag from a {@link GroupPointer} */
67
+ export function createGroupTagFromGroupPointer(group) {
68
+ return fillAndTrimTag(["group", group.id, ensureWebSocketURL(group.relay), group.name], 3);
69
+ }
@@ -20,7 +20,7 @@ export function getHighlightText(event) {
20
20
  export function getHighlightSourceEventPointer(event) {
21
21
  return getOrComputeCachedValue(event, HighlightSourceEventPointerSymbol, () => {
22
22
  const eTag = event.tags.find(isETag);
23
- return eTag ? getEventPointerFromETag(eTag) : undefined;
23
+ return eTag ? (getEventPointerFromETag(eTag) ?? undefined) : undefined;
24
24
  });
25
25
  }
26
26
  /**
@@ -30,7 +30,7 @@ export function getHighlightSourceEventPointer(event) {
30
30
  export function getHighlightSourceAddressPointer(event) {
31
31
  return getOrComputeCachedValue(event, HighlightSourceAddressPointerSymbol, () => {
32
32
  const aTag = event.tags.find(isATag);
33
- return aTag ? getAddressPointerFromATag(aTag) : undefined;
33
+ return aTag ? (getAddressPointerFromATag(aTag) ?? undefined) : undefined;
34
34
  });
35
35
  }
36
36
  /** Get the source URL that was highlighted (from 'r' tag) */
@@ -47,6 +47,8 @@ export function getHighlightAttributions(event) {
47
47
  const pTags = event.tags.filter(isPTag);
48
48
  for (const pTag of pTags) {
49
49
  const pointer = getProfilePointerFromPTag(pTag);
50
+ if (!pointer)
51
+ continue;
50
52
  const role = pTag[3] || "other"; // Role is the 4th element (index 3)
51
53
  const entry = { ...pointer, role };
52
54
  // Categorize by role
@@ -1,6 +1,6 @@
1
1
  import { getReplaceableIdentifier, isAddressableKind, isReplaceable, isReplaceableKind, } from "applesauce-core/helpers/event";
2
2
  import { getHiddenTags } from "applesauce-core/helpers/hidden-tags";
3
- import { getAddressPointerForEvent, getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag, getProfilePointerFromPTag, } from "applesauce-core/helpers/pointers";
3
+ import { getAddressPointerForEvent, getAddressPointerFromATag, getReplaceableAddressFromPointer, getEventPointerFromETag, getProfilePointerFromPTag, } from "applesauce-core/helpers/pointers";
4
4
  import { mergeRelaySets } from "applesauce-core/helpers/relays";
5
5
  import { isATag, isETag, isPTag, processTags } from "applesauce-core/helpers/tags";
6
6
  export const FAVORITE_RELAYS_KIND = 10012;
@@ -36,9 +36,9 @@ export function isEventPointerInList(list, pointer, type) {
36
36
  * @param type - Which types of tags to check
37
37
  */
38
38
  export function isAddressPointerInList(list, pointer, type) {
39
- const cord = typeof pointer === "string" ? pointer : getCoordinateFromAddressPointer(pointer);
39
+ const address = typeof pointer === "string" ? pointer : getReplaceableAddressFromPointer(pointer);
40
40
  const tags = getListTags(list, type);
41
- return tags.some((t) => t[0] === "a" && t[1] === cord);
41
+ return tags.some((t) => t[0] === "a" && t[1] === address);
42
42
  }
43
43
  /**
44
44
  * Checks if an profile pointer is anywhere in a list or set
@@ -54,9 +54,12 @@ export function isProfilePointerInList(list, pointer, type) {
54
54
  }
55
55
  /** Returns if an event is in a list */
56
56
  export function isEventInList(list, event) {
57
- return isReplaceable(event.kind)
58
- ? isAddressPointerInList(list, getAddressPointerForEvent(event))
59
- : isEventPointerInList(list, event);
57
+ if (isReplaceable(event.kind)) {
58
+ const pointer = getAddressPointerForEvent(event);
59
+ if (pointer && isAddressPointerInList(list, pointer))
60
+ return true;
61
+ }
62
+ return isEventPointerInList(list, event.id);
60
63
  }
61
64
  /**
62
65
  * Returns all the EventPointer in a list or set
@@ -64,7 +67,7 @@ export function isEventInList(list, event) {
64
67
  * @param type - Which types of tags to read
65
68
  */
66
69
  export function getEventPointersFromList(list, type) {
67
- return processTags(getListTags(list, type), (tag) => (isETag(tag) ? tag : undefined), getEventPointerFromETag);
70
+ return processTags(getListTags(list, type), (tag) => (isETag(tag) ? tag : undefined), (t) => getEventPointerFromETag(t) ?? undefined);
68
71
  }
69
72
  /**
70
73
  * Returns all the AddressPointer in a list or set
@@ -72,7 +75,7 @@ export function getEventPointersFromList(list, type) {
72
75
  * @param type - Which types of tags to read
73
76
  */
74
77
  export function getAddressPointersFromList(list, type) {
75
- return processTags(getListTags(list, type), (t) => (isATag(t) ? t : undefined), getAddressPointerFromATag);
78
+ return processTags(getListTags(list, type), (t) => (isATag(t) ? t : undefined), (t) => getAddressPointerFromATag(t) ?? undefined);
76
79
  }
77
80
  /**
78
81
  * Returns all the ProfilePointer in a list or set
@@ -80,7 +83,7 @@ export function getAddressPointersFromList(list, type) {
80
83
  * @param type - Which types of tags to read
81
84
  */
82
85
  export function getProfilePointersFromList(list, type) {
83
- return processTags(getListTags(list, type), (t) => (isPTag(t) ? t : undefined), getProfilePointerFromPTag);
86
+ return processTags(getListTags(list, type), (t) => (isPTag(t) ? t : undefined), (t) => getProfilePointerFromPTag(t) ?? undefined);
84
87
  }
85
88
  /**
86
89
  * Returns a deduplicated array of all 'relay' tags in a list or set
@@ -25,10 +25,12 @@ export function getReactionEventPointer(event) {
25
25
  const p = event.tags.find(isPTag);
26
26
  if (p) {
27
27
  const author = getProfilePointerFromPTag(p);
28
- pointer.author = author.pubkey;
29
- // Copy relay hints from "p" tag
30
- if (author.relays)
31
- pointer.relays = mergeRelaySets(author.relays, pointer.relays);
28
+ if (author) {
29
+ pointer.author = author.pubkey;
30
+ // Copy relay hints from "p" tag
31
+ if (author.relays)
32
+ pointer.relays = mergeRelaySets(author.relays, pointer.relays);
33
+ }
32
34
  }
33
35
  }
34
36
  return pointer;
@@ -47,9 +49,11 @@ export function getReactionAddressPointer(event) {
47
49
  const p = event.tags.find(isPTag);
48
50
  if (p) {
49
51
  const author = getProfilePointerFromPTag(p);
50
- // Copy relay hints from "p" tag
51
- if (author.relays)
52
- pointer.relays = mergeRelaySets(author.relays, pointer.relays);
52
+ if (author && author.pubkey === pointer.pubkey) {
53
+ // Copy relay hints from "p" tag
54
+ if (author.relays)
55
+ pointer.relays = mergeRelaySets(author.relays, pointer.relays);
56
+ }
53
57
  }
54
58
  return pointer;
55
59
  });
@@ -15,9 +15,9 @@ export function getSharedEventPointer(event) {
15
15
  const kStr = getTagValue(event, "k");
16
16
  const k = kStr ? parseInt(kStr) : undefined;
17
17
  const pointer = getEventPointerFromETag(e);
18
- if (k !== undefined)
18
+ if (pointer && k !== undefined)
19
19
  pointer.kind = k;
20
- return pointer;
20
+ return pointer ?? undefined;
21
21
  });
22
22
  }
23
23
  /** Returns the address pointer of a kind 6 or 16 share event */
@@ -26,7 +26,7 @@ export function getSharedAddressPointer(event) {
26
26
  const a = event.tags.find(isATag);
27
27
  if (!a)
28
28
  return undefined;
29
- return getAddressPointerFromATag(a);
29
+ return getAddressPointerFromATag(a) ?? undefined;
30
30
  });
31
31
  }
32
32
  /** Returns the stringified event in the content of a kind 6 or 16 share event */
@@ -5,5 +5,5 @@ export function getStreamChatMessageStream(message) {
5
5
  const tag = message.tags.find(isATag);
6
6
  if (!tag)
7
7
  return undefined;
8
- return getAddressPointerFromATag(tag);
8
+ return getAddressPointerFromATag(tag) ?? undefined;
9
9
  }
@@ -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,5 @@ 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";
5
6
  import "./register.js";
package/dist/index.js CHANGED
@@ -2,5 +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";
5
6
  // Register the common models and blueprints with the event store and event factory
6
7
  import "./register.js";
@@ -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,6 @@ 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 "./relays.js";
16
+ export * from "./stream.js";
15
17
  import "../register.js";
@@ -12,5 +12,7 @@ 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 "./relays.js";
16
+ export * from "./stream.js";
15
17
  // Register the common models with the event store
16
18
  import "../register.js";
@@ -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,36 @@
1
+ import { kinds } from "applesauce-core/helpers/event";
2
+ import { watchEventUpdates } from "applesauce-core/observable";
3
+ import { identity, map } from "rxjs";
4
+ import { FAVORITE_RELAYS_KIND, getAddressPointersFromList, getRelaysFromList } from "../helpers/lists.js";
5
+ /**
6
+ * A model that returns all favorite relays for a pubkey
7
+ * @param pubkey - The pubkey to get the favorite relays for
8
+ * @param type - Which types of tags to read
9
+ */
10
+ export function FavoriteRelaysModel(pubkey, type) {
11
+ return (events) => events.replaceable(FAVORITE_RELAYS_KIND, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
12
+ }
13
+ /**
14
+ * A model that returns all favorite relay sets for a pubkey
15
+ * @param pubkey - The pubkey to get the favorite relay sets for
16
+ * @param type - Which types of tags to read
17
+ */
18
+ export function FavoriteRelaySetsModel(pubkey, type) {
19
+ return (events) => events.replaceable(FAVORITE_RELAYS_KIND, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getAddressPointersFromList(e, type)));
20
+ }
21
+ /**
22
+ * A model that returns all search relays for a pubkey
23
+ * @param pubkey - The pubkey to get the search relays for
24
+ * @param type - Which types of tags to read
25
+ */
26
+ export function SearchRelaysModel(pubkey, type) {
27
+ return (events) => events.replaceable(kinds.SearchRelaysList, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
28
+ }
29
+ /**
30
+ * A model that returns all blocked relays for a pubkey
31
+ * @param pubkey - The pubkey to get the blocked relays for
32
+ * @param type - Which types of tags to read
33
+ */
34
+ export function BlockedRelaysModel(pubkey, type) {
35
+ return (events) => events.replaceable(kinds.BlockedRelaysList, pubkey).pipe(type !== "public" ? watchEventUpdates(events) : map(identity), map((e) => e && getRelaysFromList(e, type)));
36
+ }
@@ -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,6 +1,6 @@
1
1
  import { createReplaceableAddress, getEventUID, isEvent, kinds } from "applesauce-core/helpers/event";
2
2
  import { getTagValue } from "applesauce-core/helpers/event";
3
- import { getCoordinateFromAddressPointer, isAddressPointer, isEventPointer, } from "applesauce-core/helpers/pointers";
3
+ import { getReplaceableAddressFromPointer, isAddressPointer, isEventPointer, } from "applesauce-core/helpers/pointers";
4
4
  import { isAddressableKind } from "applesauce-core/helpers/event";
5
5
  import { map } from "rxjs/operators";
6
6
  import { COMMENT_KIND } from "../helpers/comment.js";
@@ -19,7 +19,7 @@ export function ThreadModel(root, opts) {
19
19
  const rootFilter = {};
20
20
  const replyFilter = { kinds };
21
21
  if (isAddressPointer(root)) {
22
- rootUID = getCoordinateFromAddressPointer(root);
22
+ rootUID = getReplaceableAddressFromPointer(root);
23
23
  rootFilter.kinds = [root.kind];
24
24
  rootFilter.authors = [root.pubkey];
25
25
  rootFilter["#d"] = [root.identifier];
@@ -45,7 +45,7 @@ export function ThreadModel(root, opts) {
45
45
  }
46
46
  // add item to parent
47
47
  if (refs.reply?.e || refs.reply?.a) {
48
- let uid = refs.reply.e ? refs.reply.e.id : getCoordinateFromAddressPointer(refs.reply.a);
48
+ let uid = refs.reply.e ? refs.reply.e.id : getReplaceableAddressFromPointer(refs.reply.a);
49
49
  item.parent = items.get(uid);
50
50
  if (item.parent) {
51
51
  item.parent.replies.add(item);
@@ -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,6 @@
1
+ import { IAsyncEventStore, IEventModelMixin, IEventStore } from "applesauce-core";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { ProfilePointer } from "applesauce-core/helpers/pointers";
4
+ import { MonoTypeOperatorFunction } from "rxjs";
5
+ /** Filters a timeline of events by a users mutes */
6
+ export declare function filterTimelineByMutes<T extends NostrEvent>(eventStore: IEventModelMixin<IEventStore | IAsyncEventStore>, user: string | ProfilePointer): MonoTypeOperatorFunction<T[]>;
@@ -0,0 +1,7 @@
1
+ import { combineLatest, map } from "rxjs";
2
+ import { matchMutes } from "../helpers/mute.js";
3
+ import { MuteModel } from "../models/mutes.js";
4
+ /** Filters a timeline of events by a users mutes */
5
+ export function filterTimelineByMutes(eventStore, user) {
6
+ return (source) => combineLatest([source, eventStore.model(MuteModel, user)]).pipe(map(([source, mutes]) => (mutes ? source.filter((event) => matchMutes(mutes, event)) : source)));
7
+ }
@@ -0,0 +1 @@
1
+ export * from "./filter-timeline-by-mutes.js";
@@ -0,0 +1 @@
1
+ export * from "./filter-timeline-by-mutes.js";
@@ -16,6 +16,8 @@ export function setCalendarEvent(pointer, relay) {
16
16
  if (pointer.kind !== DATE_BASED_CALENDAR_EVENT_KIND && pointer.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
17
17
  throw new Error("RSVP pointer must be to a calendar event");
18
18
  let addressPointer = isAddressPointer(pointer) ? pointer : getAddressPointerForEvent(pointer);
19
+ if (addressPointer === null)
20
+ throw new Error("Calendar event is not addressable");
19
21
  let eventPointer = isAddressPointer(pointer)
20
22
  ? undefined
21
23
  : { id: pointer.id, kind: pointer.kind, author: pointer.pubkey };
@@ -1,4 +1,3 @@
1
- import { getAddressPointerForEvent, isAddressPointer } from "applesauce-core/helpers/pointers";
2
1
  import { addAddressPointerTag, removeAddressPointerTag } from "applesauce-core/operations/tag/common";
3
2
  import { includeSingletonTag, modifyPublicTags } from "applesauce-core/operations/tags";
4
3
  /** Sets the title of a calendar */
@@ -7,9 +6,9 @@ export function setTitle(title) {
7
6
  }
8
7
  /** Adds a calendar event tags to a calendar event */
9
8
  export function addEvent(event) {
10
- return modifyPublicTags(addAddressPointerTag(isAddressPointer(event) ? event : getAddressPointerForEvent(event)));
9
+ return modifyPublicTags(addAddressPointerTag(event));
11
10
  }
12
11
  /** Removes a calendar event tags from a calendar event */
13
12
  export function removeEvent(event) {
14
- return modifyPublicTags(removeAddressPointerTag(isAddressPointer(event) ? event : getAddressPointerForEvent(event)));
13
+ return modifyPublicTags(removeAddressPointerTag(event));
15
14
  }
@@ -1,5 +1,5 @@
1
1
  import { kinds } from "applesauce-core/helpers/event";
2
- import { getCoordinateFromAddressPointer } from "applesauce-core/helpers/pointers";
2
+ import { getReplaceableAddressFromPointer } from "applesauce-core/helpers/pointers";
3
3
  import { fillAndTrimTag } from "applesauce-core/helpers/tags";
4
4
  import { includeSingletonTag } from "applesauce-core/operations/tags";
5
5
  // A list of event kinds to never attach the "client" tag to
@@ -11,7 +11,7 @@ export function setClient(name, pointer, replace = true) {
11
11
  return draft;
12
12
  else {
13
13
  const coordinate = pointer
14
- ? getCoordinateFromAddressPointer({
14
+ ? getReplaceableAddressFromPointer({
15
15
  pubkey: pointer.pubkey,
16
16
  identifier: pointer.identifier,
17
17
  kind: kinds.Handlerinformation,
@@ -1,6 +1,6 @@
1
1
  import { ensureNamedValueTag } from "applesauce-core/helpers";
2
2
  import { includeSingletonTag, modifyPublicTags } from "applesauce-core/operations/tags";
3
- import { createGroupHTagFromGroupPointer, createGroupTagFromGroupPointer } from "../helpers/groups-helper.js";
3
+ import { createGroupHTagFromGroupPointer, createGroupTagFromGroupPointer } from "../helpers/groups.js";
4
4
  /** Adds a "group" tag to a list */
5
5
  export function addGroupTag(group) {
6
6
  return modifyPublicTags((tags) => {
@@ -10,18 +10,34 @@ export function setHighlightContent(content) {
10
10
  /** Sets the source event that was highlighted using an 'e' tag */
11
11
  export function setSource(source) {
12
12
  if (isEvent(source)) {
13
- if (isReplaceable(source.kind))
14
- return modifyPublicTags(addEventPointerTag(source, true), addAddressPointerTag(getAddressPointerForEvent(source), true));
15
- else
13
+ if (isReplaceable(source.kind)) {
14
+ const address = getAddressPointerForEvent(source);
15
+ if (address) {
16
+ // Include both the event pointer and address pointer
17
+ return modifyPublicTags(addEventPointerTag(source, true), addAddressPointerTag(address, true));
18
+ }
19
+ else {
20
+ // Just include the event pointer
21
+ return modifyPublicTags(addEventPointerTag(source, true));
22
+ }
23
+ }
24
+ else {
25
+ // Include the event pointer for normal events
16
26
  return modifyPublicTags(addEventPointerTag(source, true));
27
+ }
17
28
  }
18
29
  else if (isAddressPointer(source)) {
30
+ // Include "a" tag for address pointers
19
31
  return modifyPublicTags(addAddressPointerTag(source, true));
20
32
  }
21
- else if (isEventPointer(source))
33
+ else if (isEventPointer(source)) {
34
+ // Include "e" tag for event pointers
22
35
  return modifyPublicTags(addEventPointerTag(source, true));
23
- else if (typeof source === "string")
36
+ }
37
+ else if (typeof source === "string") {
38
+ // Include "r" tags for URLs
24
39
  return includeSingletonTag(["r", source]);
40
+ }
25
41
  else
26
42
  throw new Error("Invalid source");
27
43
  }
@@ -3,9 +3,15 @@ import { getAddressPointerForEvent } from "applesauce-core/helpers/pointers";
3
3
  /** Includes the "a" tag for live streams */
4
4
  export function includeLiveStreamTag(stream) {
5
5
  return async (draft, ctx) => {
6
- let tags = Array.from(draft.tags);
7
- const hint = await ctx.getEventRelayHint?.(stream.id);
8
- tags = ensureMarkedAddressPointerTag(tags, getAddressPointerForEvent(stream, hint ? [hint] : undefined), "root");
9
- return { ...draft, tags };
6
+ const pointer = getAddressPointerForEvent(stream);
7
+ if (!pointer)
8
+ throw new Error("Stream is not addressable");
9
+ // add relay hint if there isn't one
10
+ if (pointer.relays?.[0] === undefined && ctx.getEventRelayHint) {
11
+ const hint = await ctx.getEventRelayHint(stream.id);
12
+ if (hint)
13
+ pointer.relays = [hint];
14
+ }
15
+ return { ...draft, tags: ensureMarkedAddressPointerTag(draft.tags, pointer, "root") };
10
16
  };
11
17
  }
@@ -12,7 +12,9 @@ export function setShareTags(event) {
12
12
  tags = ensureEventPointerTag(tags, getEventPointerForEvent(event, hint ? [hint] : undefined));
13
13
  // add "a" tag
14
14
  if (isAddressableKind(event.kind)) {
15
- tags = ensureAddressPointerTag(tags, getAddressPointerForEvent(event, hint ? [hint] : undefined));
15
+ const pointer = getAddressPointerForEvent(event, hint ? [hint] : undefined);
16
+ if (pointer)
17
+ tags = ensureAddressPointerTag(tags, pointer);
16
18
  }
17
19
  // add "p" tag for notify
18
20
  const pubkeyHint = await ctx.getPubkeyRelayHint?.(event.pubkey);
@@ -1,7 +1,8 @@
1
+ import { EventOperation } from "applesauce-core";
1
2
  import { NostrEvent } from "applesauce-core/helpers/event";
2
3
  import { AddressPointer } from "applesauce-core/helpers/pointers";
3
4
  import { TextContentOptions } from "applesauce-core/operations/content";
4
5
  /** Sets the message content for a stream chat event */
5
- export declare function setMessage(content: string, options?: TextContentOptions): import("applesauce-core").EventOperation;
6
+ export declare function setMessage(content: string, options?: TextContentOptions): EventOperation;
6
7
  /** Sets the stream for a stream chat event */
7
- export declare function setStream(stream: AddressPointer | NostrEvent): import("applesauce-core").EventOperation<import("nostr-tools").Event | import("nostr-tools/core").UnsignedEvent | import("nostr-tools/core").EventTemplate, import("nostr-tools").Event | import("nostr-tools/core").UnsignedEvent | import("nostr-tools/core").EventTemplate>;
8
+ export declare function setStream(stream: AddressPointer | NostrEvent): EventOperation;
@@ -21,7 +21,12 @@ export function setMessage(content, options) {
21
21
  }
22
22
  /** Sets the stream for a stream chat event */
23
23
  export function setStream(stream) {
24
+ let pointer;
24
25
  if (!isAddressPointer(stream))
25
- stream = getAddressPointerForEvent(stream);
26
- return modifyPublicTags((tags) => ensureAddressPointerTag(tags, stream));
26
+ pointer = getAddressPointerForEvent(stream);
27
+ else
28
+ pointer = stream;
29
+ if (pointer === null)
30
+ throw new Error("Stream is not an addressable event");
31
+ return modifyPublicTags((tags) => ensureAddressPointerTag(tags, pointer));
27
32
  }
@@ -1,4 +1,4 @@
1
- import { isReplaceable } from "applesauce-core/helpers";
1
+ import { tagPipe } from "applesauce-core/helpers";
2
2
  import { kinds } from "applesauce-core/helpers/event";
3
3
  import { getAddressPointerForEvent } from "applesauce-core/helpers/pointers";
4
4
  import { addAddressPointerTag, addEventPointerTag, removeAddressPointerTag, removeEventPointerTag, } from "applesauce-core/operations/tag/common";
@@ -6,15 +6,17 @@ import { addAddressPointerTag, addEventPointerTag, removeAddressPointerTag, remo
6
6
  export function addEventBookmarkTag(event) {
7
7
  if (event.kind !== kinds.ShortTextNote && event.kind !== kinds.LongFormArticle)
8
8
  throw new Error(`Event kind (${event.kind}) cant not be added to bookmarks`);
9
- return isReplaceable(event.kind)
10
- ? addAddressPointerTag(getAddressPointerForEvent(event))
11
- : addEventPointerTag(event.id);
9
+ const address = getAddressPointerForEvent(event);
10
+ return address ? addAddressPointerTag(address) : addEventPointerTag(event.id);
12
11
  }
13
12
  /** Removes an "e" or "a" tag from a bookmark list or set */
14
13
  export function removeEventBookmarkTag(event) {
15
14
  if (event.kind !== kinds.ShortTextNote && event.kind !== kinds.LongFormArticle)
16
15
  throw new Error(`Event kind (${event.kind}) cant not be added to bookmarks`);
17
- return isReplaceable(event.kind)
18
- ? removeAddressPointerTag(getAddressPointerForEvent(event))
19
- : removeEventPointerTag(event.id);
16
+ const address = getAddressPointerForEvent(event);
17
+ return tagPipe(
18
+ // Remove address pointer if it exists
19
+ address ? removeAddressPointerTag(address) : undefined,
20
+ // Always remove event pointer
21
+ removeEventPointerTag(event.id));
20
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-common",
3
- "version": "0.0.0-next-20251203172109",
3
+ "version": "0.0.0-next-20251209200210",
4
4
  "description": "Common NIP-specific helpers and models for applesauce",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -59,23 +59,38 @@
59
59
  "import": "./dist/blueprints/*.js",
60
60
  "require": "./dist/blueprints/*.js",
61
61
  "types": "./dist/blueprints/*.d.ts"
62
+ },
63
+ "./observable": {
64
+ "import": "./dist/observable/index.js",
65
+ "require": "./dist/observable/index.js",
66
+ "types": "./dist/observable/index.d.ts"
67
+ },
68
+ "./observable/*": {
69
+ "import": "./dist/observable/*.js",
70
+ "require": "./dist/observable/*.js",
71
+ "types": "./dist/observable/*.d.ts"
62
72
  }
63
73
  },
64
74
  "dependencies": {
65
75
  "@scure/base": "^1.2.4",
66
- "applesauce-core": "0.0.0-next-20251203172109",
76
+ "applesauce-core": "0.0.0-next-20251209200210",
67
77
  "hash-sum": "^2.0.0",
68
78
  "light-bolt11-decoder": "^3.2.0",
69
79
  "rxjs": "^7.8.1"
70
80
  },
71
81
  "devDependencies": {
72
82
  "@hirez_io/observer-spy": "^2.2.0",
83
+ "@nostrability/schemata": "github:nostrability/schemata",
73
84
  "@types/debug": "^4.1.12",
74
85
  "@types/hash-sum": "^1.0.2",
86
+ "@types/node": "^22.19.1",
87
+ "ajv": "^8.17.1",
88
+ "ajv-formats": "^3.0.1",
75
89
  "nostr-tools": "^2.18",
76
90
  "rimraf": "^6.0.1",
77
91
  "typescript": "^5.8.3",
78
- "vitest": "^4.0.15"
92
+ "vitest": "^4.0.15",
93
+ "yaml": "^2.8.2"
79
94
  },
80
95
  "funding": {
81
96
  "type": "lightning",
@@ -1,6 +0,0 @@
1
- import { NameValueTag } from "applesauce-core/helpers";
2
- import { GroupPointer } from "./groups.js";
3
- /** Creates a "h" tag for chat messages from a {@link GroupPointer} */
4
- export declare function createGroupHTagFromGroupPointer(group: GroupPointer): NameValueTag;
5
- /** Creates a "group" tag from a {@link GroupPointer} */
6
- export declare function createGroupTagFromGroupPointer(group: GroupPointer): NameValueTag;
@@ -1,9 +0,0 @@
1
- import { ensureWebSocketURL, fillAndTrimTag } from "applesauce-core/helpers";
2
- /** Creates a "h" tag for chat messages from a {@link GroupPointer} */
3
- export function createGroupHTagFromGroupPointer(group) {
4
- return fillAndTrimTag(["h", group.id, ensureWebSocketURL(group.relay)]);
5
- }
6
- /** Creates a "group" tag from a {@link GroupPointer} */
7
- export function createGroupTagFromGroupPointer(group) {
8
- return fillAndTrimTag(["group", group.id, ensureWebSocketURL(group.relay), group.name], 3);
9
- }