applesauce-common 0.0.0-next-20251203172109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/blueprints/app-data.d.ts +5 -0
  4. package/dist/blueprints/app-data.js +10 -0
  5. package/dist/blueprints/calendar.d.ts +5 -0
  6. package/dist/blueprints/calendar.js +7 -0
  7. package/dist/blueprints/channels.d.ts +6 -0
  8. package/dist/blueprints/channels.js +13 -0
  9. package/dist/blueprints/comment.d.ts +12 -0
  10. package/dist/blueprints/comment.js +15 -0
  11. package/dist/blueprints/delete.d.ts +9 -0
  12. package/dist/blueprints/delete.js +14 -0
  13. package/dist/blueprints/file-metadata.d.ts +8 -0
  14. package/dist/blueprints/file-metadata.js +11 -0
  15. package/dist/blueprints/follow-set.d.ts +11 -0
  16. package/dist/blueprints/follow-set.js +21 -0
  17. package/dist/blueprints/gift-wrap.d.ts +5 -0
  18. package/dist/blueprints/gift-wrap.js +6 -0
  19. package/dist/blueprints/group.d.ts +9 -0
  20. package/dist/blueprints/group.js +17 -0
  21. package/dist/blueprints/highlight.d.ts +20 -0
  22. package/dist/blueprints/highlight.js +12 -0
  23. package/dist/blueprints/index.d.ts +23 -0
  24. package/dist/blueprints/index.js +24 -0
  25. package/dist/blueprints/legacy-message.d.ts +7 -0
  26. package/dist/blueprints/legacy-message.js +29 -0
  27. package/dist/blueprints/live-stream.d.ts +6 -0
  28. package/dist/blueprints/live-stream.js +9 -0
  29. package/dist/blueprints/note.d.ts +16 -0
  30. package/dist/blueprints/note.js +30 -0
  31. package/dist/blueprints/picture-post.d.ts +12 -0
  32. package/dist/blueprints/picture-post.js +17 -0
  33. package/dist/blueprints/poll.d.ts +41 -0
  34. package/dist/blueprints/poll.js +33 -0
  35. package/dist/blueprints/profile.d.ts +3 -0
  36. package/dist/blueprints/profile.js +7 -0
  37. package/dist/blueprints/reaction.d.ts +10 -0
  38. package/dist/blueprints/reaction.js +14 -0
  39. package/dist/blueprints/share.d.ts +12 -0
  40. package/dist/blueprints/share.js +25 -0
  41. package/dist/blueprints/stream.d.ts +6 -0
  42. package/dist/blueprints/stream.js +7 -0
  43. package/dist/blueprints/torrent.d.ts +23 -0
  44. package/dist/blueprints/torrent.js +25 -0
  45. package/dist/blueprints/wrapped-message.d.ts +20 -0
  46. package/dist/blueprints/wrapped-message.js +64 -0
  47. package/dist/helpers/app-data.d.ts +39 -0
  48. package/dist/helpers/app-data.js +68 -0
  49. package/dist/helpers/app-handler.d.ts +22 -0
  50. package/dist/helpers/app-handler.js +67 -0
  51. package/dist/helpers/article.d.ts +14 -0
  52. package/dist/helpers/article.js +24 -0
  53. package/dist/helpers/blossom.d.ts +11 -0
  54. package/dist/helpers/blossom.js +40 -0
  55. package/dist/helpers/bolt11.d.ts +10 -0
  56. package/dist/helpers/bolt11.js +17 -0
  57. package/dist/helpers/bookmark.d.ts +30 -0
  58. package/dist/helpers/bookmark.js +96 -0
  59. package/dist/helpers/calendar-event.d.ts +39 -0
  60. package/dist/helpers/calendar-event.js +121 -0
  61. package/dist/helpers/calendar-rsvp.d.ts +15 -0
  62. package/dist/helpers/calendar-rsvp.js +38 -0
  63. package/dist/helpers/calendar.d.ts +6 -0
  64. package/dist/helpers/calendar.js +11 -0
  65. package/dist/helpers/channels.d.ts +13 -0
  66. package/dist/helpers/channels.js +27 -0
  67. package/dist/helpers/comment.d.ts +47 -0
  68. package/dist/helpers/comment.js +185 -0
  69. package/dist/helpers/content.d.ts +3 -0
  70. package/dist/helpers/content.js +8 -0
  71. package/dist/helpers/emoji.d.ts +21 -0
  72. package/dist/helpers/emoji.js +34 -0
  73. package/dist/helpers/encrypted-content-cache.d.ts +22 -0
  74. package/dist/helpers/encrypted-content-cache.js +138 -0
  75. package/dist/helpers/file-metadata.d.ts +55 -0
  76. package/dist/helpers/file-metadata.js +130 -0
  77. package/dist/helpers/gift-wrap.d.ts +66 -0
  78. package/dist/helpers/gift-wrap.js +204 -0
  79. package/dist/helpers/groups-helper.d.ts +6 -0
  80. package/dist/helpers/groups-helper.js +9 -0
  81. package/dist/helpers/groups.d.ts +26 -0
  82. package/dist/helpers/groups.js +49 -0
  83. package/dist/helpers/hashtag.d.ts +2 -0
  84. package/dist/helpers/hashtag.js +7 -0
  85. package/dist/helpers/highlight.d.ts +45 -0
  86. package/dist/helpers/highlight.js +76 -0
  87. package/dist/helpers/index.d.ts +37 -0
  88. package/dist/helpers/index.js +37 -0
  89. package/dist/helpers/legacy-messages.d.ts +31 -0
  90. package/dist/helpers/legacy-messages.js +49 -0
  91. package/dist/helpers/lists.d.ts +58 -0
  92. package/dist/helpers/lists.js +110 -0
  93. package/dist/helpers/lnurl.d.ts +8 -0
  94. package/dist/helpers/lnurl.js +44 -0
  95. package/dist/helpers/mailboxes.d.ts +7 -0
  96. package/dist/helpers/mailboxes.js +49 -0
  97. package/dist/helpers/messages.d.ts +31 -0
  98. package/dist/helpers/messages.js +57 -0
  99. package/dist/helpers/mute.d.ts +33 -0
  100. package/dist/helpers/mute.js +111 -0
  101. package/dist/helpers/picture-post.d.ts +5 -0
  102. package/dist/helpers/picture-post.js +6 -0
  103. package/dist/helpers/poll.d.ts +46 -0
  104. package/dist/helpers/poll.js +78 -0
  105. package/dist/helpers/reaction.d.ts +8 -0
  106. package/dist/helpers/reaction.js +56 -0
  107. package/dist/helpers/relay-discovery.d.ts +87 -0
  108. package/dist/helpers/relay-discovery.js +126 -0
  109. package/dist/helpers/reports.d.ts +28 -0
  110. package/dist/helpers/reports.js +38 -0
  111. package/dist/helpers/share.d.ts +19 -0
  112. package/dist/helpers/share.js +58 -0
  113. package/dist/helpers/stream-chat.d.ts +4 -0
  114. package/dist/helpers/stream-chat.js +9 -0
  115. package/dist/helpers/stream.d.ts +31 -0
  116. package/dist/helpers/stream.js +81 -0
  117. package/dist/helpers/threading.d.ts +55 -0
  118. package/dist/helpers/threading.js +94 -0
  119. package/dist/helpers/torrent.d.ts +55 -0
  120. package/dist/helpers/torrent.js +270 -0
  121. package/dist/helpers/user-status.d.ts +18 -0
  122. package/dist/helpers/user-status.js +22 -0
  123. package/dist/helpers/wrapped-messages.d.ts +14 -0
  124. package/dist/helpers/wrapped-messages.js +23 -0
  125. package/dist/helpers/zap.d.ts +46 -0
  126. package/dist/helpers/zap.js +125 -0
  127. package/dist/index.d.ts +5 -0
  128. package/dist/index.js +6 -0
  129. package/dist/models/blossom.d.ts +11 -0
  130. package/dist/models/blossom.js +18 -0
  131. package/dist/models/bookmarks.d.ts +8 -0
  132. package/dist/models/bookmarks.js +24 -0
  133. package/dist/models/calendar.d.ts +6 -0
  134. package/dist/models/calendar.js +15 -0
  135. package/dist/models/channels.d.ts +11 -0
  136. package/dist/models/channels.js +61 -0
  137. package/dist/models/comments.d.ts +11 -0
  138. package/dist/models/comments.js +17 -0
  139. package/dist/models/gift-wrap.d.ts +7 -0
  140. package/dist/models/gift-wrap.js +20 -0
  141. package/dist/models/index.d.ts +15 -0
  142. package/dist/models/index.js +16 -0
  143. package/dist/models/legacy-messages.d.ts +14 -0
  144. package/dist/models/legacy-messages.js +64 -0
  145. package/dist/models/mutes.d.ts +16 -0
  146. package/dist/models/mutes.js +34 -0
  147. package/dist/models/pins.d.ts +4 -0
  148. package/dist/models/pins.js +10 -0
  149. package/dist/models/reactions.d.ts +11 -0
  150. package/dist/models/reactions.js +21 -0
  151. package/dist/models/thread.d.ts +33 -0
  152. package/dist/models/thread.js +93 -0
  153. package/dist/models/user-status.d.ts +11 -0
  154. package/dist/models/user-status.js +32 -0
  155. package/dist/models/wrapped-messages.d.ts +31 -0
  156. package/dist/models/wrapped-messages.js +76 -0
  157. package/dist/models/zaps.d.ts +9 -0
  158. package/dist/models/zaps.js +26 -0
  159. package/dist/operations/app-data.d.ts +6 -0
  160. package/dist/operations/app-data.js +21 -0
  161. package/dist/operations/blossom.d.ts +5 -0
  162. package/dist/operations/blossom.js +13 -0
  163. package/dist/operations/calendar-event.d.ts +34 -0
  164. package/dist/operations/calendar-event.js +72 -0
  165. package/dist/operations/calendar-rsvp.d.ts +10 -0
  166. package/dist/operations/calendar-rsvp.js +35 -0
  167. package/dist/operations/calendar.d.ts +9 -0
  168. package/dist/operations/calendar.js +15 -0
  169. package/dist/operations/channel.d.ts +4 -0
  170. package/dist/operations/channel.js +10 -0
  171. package/dist/operations/client.d.ts +4 -0
  172. package/dist/operations/client.js +23 -0
  173. package/dist/operations/comment.d.ts +4 -0
  174. package/dist/operations/comment.js +11 -0
  175. package/dist/operations/file-metadata.d.ts +4 -0
  176. package/dist/operations/file-metadata.js +21 -0
  177. package/dist/operations/geohash.d.ts +5 -0
  178. package/dist/operations/geohash.js +17 -0
  179. package/dist/operations/gift-wrap.d.ts +13 -0
  180. package/dist/operations/gift-wrap.js +93 -0
  181. package/dist/operations/group.d.ts +11 -0
  182. package/dist/operations/group.js +34 -0
  183. package/dist/operations/hashtags.d.ts +7 -0
  184. package/dist/operations/hashtags.js +17 -0
  185. package/dist/operations/highlight.d.ts +18 -0
  186. package/dist/operations/highlight.js +47 -0
  187. package/dist/operations/index.d.ts +28 -0
  188. package/dist/operations/index.js +28 -0
  189. package/dist/operations/legacy-message.d.ts +6 -0
  190. package/dist/operations/legacy-message.js +13 -0
  191. package/dist/operations/list.d.ts +7 -0
  192. package/dist/operations/list.js +14 -0
  193. package/dist/operations/live-stream.d.ts +4 -0
  194. package/dist/operations/live-stream.js +11 -0
  195. package/dist/operations/media-attachment.d.ts +4 -0
  196. package/dist/operations/media-attachment.js +12 -0
  197. package/dist/operations/note.d.ts +9 -0
  198. package/dist/operations/note.js +42 -0
  199. package/dist/operations/picture-post.d.ts +4 -0
  200. package/dist/operations/picture-post.js +14 -0
  201. package/dist/operations/poll-response.d.ts +9 -0
  202. package/dist/operations/poll-response.js +20 -0
  203. package/dist/operations/poll.d.ts +19 -0
  204. package/dist/operations/poll.js +42 -0
  205. package/dist/operations/reaction.d.ts +7 -0
  206. package/dist/operations/reaction.js +39 -0
  207. package/dist/operations/share.d.ts +8 -0
  208. package/dist/operations/share.js +34 -0
  209. package/dist/operations/stream-chat.d.ts +7 -0
  210. package/dist/operations/stream-chat.js +27 -0
  211. package/dist/operations/stream.d.ts +41 -0
  212. package/dist/operations/stream.js +83 -0
  213. package/dist/operations/tag/bookmarks.d.ts +6 -0
  214. package/dist/operations/tag/bookmarks.js +20 -0
  215. package/dist/operations/tag/index.d.ts +1 -0
  216. package/dist/operations/tag/index.js +1 -0
  217. package/dist/operations/torrent.d.ts +33 -0
  218. package/dist/operations/torrent.js +66 -0
  219. package/dist/operations/wrapped-message.d.ts +12 -0
  220. package/dist/operations/wrapped-message.js +28 -0
  221. package/dist/operations/zap-split.d.ts +10 -0
  222. package/dist/operations/zap-split.js +20 -0
  223. package/dist/register.d.ts +11 -0
  224. package/dist/register.js +13 -0
  225. package/package.json +91 -0
@@ -0,0 +1,96 @@
1
+ import { getOrComputeCachedValue, notifyEventUpdate } from "applesauce-core/helpers";
2
+ import { kinds } from "applesauce-core/helpers/event";
3
+ import { getHiddenTags, isHiddenTagsUnlocked, unlockHiddenTags } from "applesauce-core/helpers/hidden-tags";
4
+ import { getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag, mergeAddressPointers, mergeEventPointers, } from "applesauce-core/helpers/pointers";
5
+ export const BookmarkPublicSymbol = Symbol.for("bookmark-public");
6
+ export const BookmarkHiddenSymbol = Symbol.for("bookmark-hidden");
7
+ /** Parses an array of tags into a {@link Bookmarks} object */
8
+ export function parseBookmarkTags(tags) {
9
+ const notes = tags.filter((t) => t[0] === "e" && t[1]).map(getEventPointerFromETag);
10
+ const articles = tags
11
+ .filter((t) => t[0] === "a" && t[1])
12
+ .map(getAddressPointerFromATag)
13
+ .filter((addr) => addr.kind === kinds.LongFormArticle);
14
+ const hashtags = tags.filter((t) => t[0] === "t" && t[1]).map((t) => t[1]);
15
+ const urls = tags.filter((t) => t[0] === "r" && t[1]).map((t) => t[1]);
16
+ return { notes, articles, hashtags, urls };
17
+ }
18
+ /** Merges any number of {@link Bookmarks} objects */
19
+ export function mergeBookmarks(...bookmarks) {
20
+ const notes = new Map();
21
+ const articles = new Map();
22
+ const hashtags = new Set();
23
+ const urls = new Set();
24
+ for (const bookmark of bookmarks) {
25
+ if (!bookmark)
26
+ continue;
27
+ for (const note of bookmark.notes) {
28
+ const existing = notes.get(note.id);
29
+ if (existing)
30
+ notes.set(note.id, mergeEventPointers(existing, note));
31
+ else
32
+ notes.set(note.id, note);
33
+ }
34
+ for (const article of bookmark.articles) {
35
+ const coord = getCoordinateFromAddressPointer(article);
36
+ const existing = articles.get(coord);
37
+ if (existing)
38
+ articles.set(coord, mergeAddressPointers(existing, article));
39
+ else
40
+ articles.set(coord, article);
41
+ }
42
+ for (const hashtag of bookmark.hashtags)
43
+ hashtags.add(hashtag);
44
+ for (const url of bookmark.urls)
45
+ urls.add(url);
46
+ }
47
+ return {
48
+ notes: Array.from(notes.values()),
49
+ articles: Array.from(articles.values()),
50
+ hashtags: Array.from(hashtags),
51
+ urls: Array.from(urls),
52
+ };
53
+ }
54
+ /** Returns all the bookmarks of the event */
55
+ export function getBookmarks(bookmark) {
56
+ const hidden = getHiddenBookmarks(bookmark);
57
+ if (hidden)
58
+ return mergeBookmarks(hidden, getPublicBookmarks(bookmark));
59
+ else
60
+ return getPublicBookmarks(bookmark);
61
+ }
62
+ /** Returns the public bookmarks of the event */
63
+ export function getPublicBookmarks(bookmark) {
64
+ return getOrComputeCachedValue(bookmark, BookmarkPublicSymbol, () => parseBookmarkTags(bookmark.tags));
65
+ }
66
+ /** Checks if the hidden bookmarks are unlocked */
67
+ export function isHiddenBookmarksUnlocked(bookmark) {
68
+ return isHiddenTagsUnlocked(bookmark) && Reflect.has(bookmark, BookmarkHiddenSymbol);
69
+ }
70
+ export function getHiddenBookmarks(bookmark) {
71
+ if (isHiddenBookmarksUnlocked(bookmark))
72
+ return bookmark[BookmarkHiddenSymbol];
73
+ //get hidden tags
74
+ const tags = getHiddenTags(bookmark);
75
+ if (!tags)
76
+ return undefined;
77
+ // parse bookmarks
78
+ const bookmarks = parseBookmarkTags(tags);
79
+ // set cached value
80
+ Reflect.set(bookmark, BookmarkHiddenSymbol, bookmarks);
81
+ return bookmarks;
82
+ }
83
+ /** Unlocks the hidden bookmarks on a bookmarks event */
84
+ export async function unlockHiddenBookmarks(bookmark, signer) {
85
+ if (isHiddenBookmarksUnlocked(bookmark))
86
+ return bookmark[BookmarkHiddenSymbol];
87
+ // unlock hidden tags
88
+ await unlockHiddenTags(bookmark, signer);
89
+ // get hidden bookmarks
90
+ const bookmarks = getHiddenBookmarks(bookmark);
91
+ if (!bookmarks)
92
+ throw new Error("Failed to unlock hidden bookmarks");
93
+ // notify event store
94
+ notifyEventUpdate(bookmark);
95
+ return bookmarks;
96
+ }
@@ -0,0 +1,39 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { ProfilePointer } from "applesauce-core/helpers/pointers";
3
+ import { NameValueTag } from "applesauce-core/helpers/tags";
4
+ export declare const DATE_BASED_CALENDAR_EVENT_KIND = 31922;
5
+ export declare const TIME_BASED_CALENDAR_EVENT_KIND = 31923;
6
+ export type CalendarEventParticipant = ProfilePointer & {
7
+ role?: string;
8
+ };
9
+ export declare const CalendarEventLocationsSymbol: unique symbol;
10
+ export declare const CalendarEventParticipantsSymbol: unique symbol;
11
+ export declare const CalendarEventHashtagsSymbol: unique symbol;
12
+ export declare const CalendarEventReferencesSymbol: unique symbol;
13
+ export declare const CalendarEventGeohashSymbol: unique symbol;
14
+ /** Gets the title of a calendar event or calendar */
15
+ export declare function getCalendarEventTitle(event: NostrEvent): string | undefined;
16
+ /** Gets the summary of a calendar event */
17
+ export declare function getCalendarEventSummary(event: NostrEvent): string | undefined;
18
+ /** Gets the image URL of a calendar event */
19
+ export declare function getCalendarEventImage(event: NostrEvent): string | undefined;
20
+ /** Gets the start Unix timestamp of a calendar event */
21
+ export declare function getCalendarEventStart(event: NostrEvent): number | undefined;
22
+ /** Gets the timezone of the start timestamp of a calendar event */
23
+ export declare function getCalendarEventStartTimezone(event: NostrEvent): string | undefined;
24
+ /** Gets the timezone of the end timestamp of a calendar event */
25
+ export declare function getCalendarEventEndTimezone(event: NostrEvent): string | undefined;
26
+ /** Gets the end Unix timestamp of a calendar event */
27
+ export declare function getCalendarEventEnd(event: NostrEvent): number | undefined;
28
+ /** Gets all locations from a calendar event */
29
+ export declare function getCalendarEventLocations(event: NostrEvent): string[];
30
+ /** Gets the geohash of a calendar event */
31
+ export declare function getCalendarEventGeohash(event: NostrEvent): string | undefined;
32
+ /** Gets all participants from a calendar event */
33
+ export declare function getCalendarEventParticipants(event: NostrEvent): CalendarEventParticipant[];
34
+ /** Gets all hashtags from a calendar event */
35
+ export declare function getCalendarEventHashtags(event: NostrEvent): string[];
36
+ /** Gets all references from a calendar event */
37
+ export declare function getCalendarEventReferences(event: NostrEvent): string[];
38
+ /** Creates a "p" tag for a calendar event participant */
39
+ export declare function createCalendarEventParticipantTag(participant: CalendarEventParticipant): NameValueTag;
@@ -0,0 +1,121 @@
1
+ import { createPTagFromProfilePointer } from "applesauce-core/helpers";
2
+ import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
3
+ import { getTagValue } from "applesauce-core/helpers/event";
4
+ import { getProfilePointerFromPTag } from "applesauce-core/helpers/pointers";
5
+ import { fillAndTrimTag, isPTag, isRTag, isTTag } from "applesauce-core/helpers/tags";
6
+ // NIP-52 Calendar Event Kinds
7
+ export const DATE_BASED_CALENDAR_EVENT_KIND = 31922;
8
+ export const TIME_BASED_CALENDAR_EVENT_KIND = 31923;
9
+ // Cache symbols for complex operations only
10
+ export const CalendarEventLocationsSymbol = Symbol.for("calendar-event-locations");
11
+ export const CalendarEventParticipantsSymbol = Symbol.for("calendar-event-participants");
12
+ export const CalendarEventHashtagsSymbol = Symbol.for("calendar-event-hashtags");
13
+ export const CalendarEventReferencesSymbol = Symbol.for("calendar-event-references");
14
+ export const CalendarEventGeohashSymbol = Symbol.for("calendar-event-geohash");
15
+ /** Gets the title of a calendar event or calendar */
16
+ export function getCalendarEventTitle(event) {
17
+ return getTagValue(event, "title") || getTagValue(event, "name"); // fallback to deprecated "name" tag
18
+ }
19
+ /** Gets the summary of a calendar event */
20
+ export function getCalendarEventSummary(event) {
21
+ return getTagValue(event, "summary");
22
+ }
23
+ /** Gets the image URL of a calendar event */
24
+ export function getCalendarEventImage(event) {
25
+ return getTagValue(event, "image");
26
+ }
27
+ /** Gets the start Unix timestamp of a calendar event */
28
+ export function getCalendarEventStart(event) {
29
+ const value = getTagValue(event, "start");
30
+ if (!value)
31
+ return undefined;
32
+ if (event.kind === DATE_BASED_CALENDAR_EVENT_KIND)
33
+ return new Date(value).valueOf() / 1000;
34
+ else if (event.kind === TIME_BASED_CALENDAR_EVENT_KIND)
35
+ return parseInt(value);
36
+ else
37
+ return undefined;
38
+ }
39
+ /** Gets the timezone of the start timestamp of a calendar event */
40
+ export function getCalendarEventStartTimezone(event) {
41
+ if (event.kind === DATE_BASED_CALENDAR_EVENT_KIND)
42
+ return undefined;
43
+ return getTagValue(event, "start_tzid");
44
+ }
45
+ /** Gets the timezone of the end timestamp of a calendar event */
46
+ export function getCalendarEventEndTimezone(event) {
47
+ if (event.kind === DATE_BASED_CALENDAR_EVENT_KIND)
48
+ return undefined;
49
+ return getTagValue(event, "end_tzid");
50
+ }
51
+ /** Gets the end Unix timestamp of a calendar event */
52
+ export function getCalendarEventEnd(event) {
53
+ const value = getTagValue(event, "end");
54
+ if (!value)
55
+ return undefined;
56
+ if (event.kind === DATE_BASED_CALENDAR_EVENT_KIND)
57
+ return new Date(value).valueOf() / 1000;
58
+ else if (event.kind === TIME_BASED_CALENDAR_EVENT_KIND)
59
+ return parseInt(value);
60
+ else
61
+ return undefined;
62
+ }
63
+ /** Gets all locations from a calendar event */
64
+ export function getCalendarEventLocations(event) {
65
+ if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
66
+ throw new Error("Event is not a date-based or time-based calendar event");
67
+ return getOrComputeCachedValue(event, CalendarEventLocationsSymbol, () => {
68
+ return event.tags.filter((t) => t[0] === "location" && t[1]).map((t) => t[1]);
69
+ });
70
+ }
71
+ /** Gets the geohash of a calendar event */
72
+ export function getCalendarEventGeohash(event) {
73
+ if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
74
+ throw new Error("Event is not a date-based or time-based calendar event");
75
+ return getOrComputeCachedValue(event, CalendarEventGeohashSymbol, () => {
76
+ let hash = undefined;
77
+ for (const tag of event.tags) {
78
+ if (tag[0] === "g" && tag[1] && (!hash || tag[1].length > hash.length))
79
+ hash = tag[1];
80
+ }
81
+ return hash;
82
+ });
83
+ }
84
+ /** Gets all participants from a calendar event */
85
+ export function getCalendarEventParticipants(event) {
86
+ if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
87
+ throw new Error("Event is not a date-based or time-based calendar event");
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
+ }));
94
+ });
95
+ }
96
+ /** Gets all hashtags from a calendar event */
97
+ export function getCalendarEventHashtags(event) {
98
+ if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
99
+ throw new Error("Event is not a date-based or time-based calendar event");
100
+ return getOrComputeCachedValue(event, CalendarEventHashtagsSymbol, () => {
101
+ return event.tags.filter(isTTag).map((t) => t[1]);
102
+ });
103
+ }
104
+ /** Gets all references from a calendar event */
105
+ export function getCalendarEventReferences(event) {
106
+ if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
107
+ throw new Error("Event is not a date-based or time-based calendar event");
108
+ return getOrComputeCachedValue(event, CalendarEventReferencesSymbol, () => {
109
+ return event.tags.filter(isRTag).map((t) => t[1]);
110
+ });
111
+ }
112
+ /** Creates a "p" tag for a calendar event participant */
113
+ export function createCalendarEventParticipantTag(participant) {
114
+ const tag = createPTagFromProfilePointer(participant);
115
+ // Add the third "role" value if set
116
+ if (participant.role) {
117
+ tag[3] = participant.role;
118
+ return fillAndTrimTag(tag, 3);
119
+ }
120
+ return tag;
121
+ }
@@ -0,0 +1,15 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { AddressPointer, EventPointer, ProfilePointer } from "applesauce-core/helpers/pointers";
3
+ export declare const CALENDAR_EVENT_RSVP_KIND = 31925;
4
+ export type RSVPStatus = "accepted" | "declined" | "tentative";
5
+ export type RSVPFreeBusy = "free" | "busy";
6
+ /** Gets the RSVP status from a calendar event RSVP */
7
+ export declare function getRSVPStatus(event: NostrEvent): RSVPStatus | undefined;
8
+ /** Gets the free/busy status from a calendar event RSVP (will be undefined if the RSVP is declined) */
9
+ export declare function getRSVPFreeBusy(event: NostrEvent): RSVPFreeBusy | undefined;
10
+ /** Gets the referenced calendar event coordinate that the RSVP is responding to */
11
+ export declare function getRSVPAddressPointer(event: NostrEvent): AddressPointer | undefined;
12
+ /** Gets the referenced calendar event pointer that the RSVP is responding to */
13
+ export declare function getRSVPEventPointer(event: NostrEvent): EventPointer | undefined;
14
+ /** Gets the profile pointer that the RSVP is responding to */
15
+ export declare function getRSVPProfilePointer(event: NostrEvent): ProfilePointer | undefined;
@@ -0,0 +1,38 @@
1
+ import { getTagValue } from "applesauce-core/helpers/event";
2
+ import { getAddressPointerFromATag, getEventPointerFromETag, getProfilePointerFromPTag, } from "applesauce-core/helpers/pointers";
3
+ import { isATag, isETag, isPTag } from "applesauce-core/helpers/tags";
4
+ export const CALENDAR_EVENT_RSVP_KIND = 31925;
5
+ /** Gets the RSVP status from a calendar event RSVP */
6
+ export function getRSVPStatus(event) {
7
+ const status = getTagValue(event, "status");
8
+ return status && ["accepted", "declined", "tentative"].includes(status) ? status : undefined;
9
+ }
10
+ /** Gets the free/busy status from a calendar event RSVP (will be undefined if the RSVP is declined) */
11
+ export function getRSVPFreeBusy(event) {
12
+ const status = getRSVPStatus(event);
13
+ if (status === "declined")
14
+ return undefined;
15
+ const fb = getTagValue(event, "fb");
16
+ return fb && ["free", "busy"].includes(fb) ? fb : undefined;
17
+ }
18
+ /** Gets the referenced calendar event coordinate that the RSVP is responding to */
19
+ export function getRSVPAddressPointer(event) {
20
+ const tag = event.tags.find(isATag);
21
+ if (!tag)
22
+ return undefined;
23
+ return getAddressPointerFromATag(tag);
24
+ }
25
+ /** Gets the referenced calendar event pointer that the RSVP is responding to */
26
+ export function getRSVPEventPointer(event) {
27
+ const tag = event.tags.find(isETag);
28
+ if (!tag)
29
+ return undefined;
30
+ return getEventPointerFromETag(tag);
31
+ }
32
+ /** Gets the profile pointer that the RSVP is responding to */
33
+ export function getRSVPProfilePointer(event) {
34
+ const tag = event.tags.find(isPTag);
35
+ if (!tag)
36
+ return undefined;
37
+ return getProfilePointerFromPTag(tag);
38
+ }
@@ -0,0 +1,6 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { AddressPointer } from "applesauce-core/helpers/pointers";
3
+ /** Gets the title of a calendar */
4
+ export declare function getCalendarTitle(event: NostrEvent): string | undefined;
5
+ /** Gets the address pointers to all the events on the calendar */
6
+ export declare function getCalendarAddressPointers(event: NostrEvent): AddressPointer[];
@@ -0,0 +1,11 @@
1
+ import { getTagValue } from "applesauce-core/helpers/event";
2
+ import { getAddressPointerFromATag } from "applesauce-core/helpers/pointers";
3
+ import { isATag } from "applesauce-core/helpers/tags";
4
+ /** Gets the title of a calendar */
5
+ export function getCalendarTitle(event) {
6
+ return getTagValue(event, "title");
7
+ }
8
+ /** Gets the address pointers to all the events on the calendar */
9
+ export function getCalendarAddressPointers(event) {
10
+ return event.tags.filter(isATag).map(getAddressPointerFromATag);
11
+ }
@@ -0,0 +1,13 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { EventPointer } from "applesauce-core/helpers/pointers";
3
+ export declare const ChannelMetadataSymbol: unique symbol;
4
+ export type ChannelMetadataContent = {
5
+ name: string;
6
+ about: string;
7
+ picture: string;
8
+ relays?: string[];
9
+ };
10
+ /** Gets the parsed metadata on a channel creation or channel metadata event */
11
+ export declare function getChannelMetadataContent(channel: NostrEvent): ChannelMetadataContent;
12
+ /** gets the EventPointer for a channel message or metadata event */
13
+ export declare function getChannelPointer(event: NostrEvent): EventPointer | undefined;
@@ -0,0 +1,27 @@
1
+ import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
2
+ export const ChannelMetadataSymbol = Symbol.for("channel-metadata");
3
+ function parseChannelMetadataContent(channel) {
4
+ const metadata = JSON.parse(channel.content);
5
+ if (metadata.name === undefined)
6
+ throw new Error("Missing name");
7
+ if (metadata.about === undefined)
8
+ throw new Error("Missing about");
9
+ if (metadata.picture === undefined)
10
+ throw new Error("Missing picture");
11
+ if (metadata.relays && !Array.isArray(metadata.relays))
12
+ throw new Error("Invalid relays");
13
+ return metadata;
14
+ }
15
+ /** Gets the parsed metadata on a channel creation or channel metadata event */
16
+ export function getChannelMetadataContent(channel) {
17
+ return getOrComputeCachedValue(channel, ChannelMetadataSymbol, () => {
18
+ return parseChannelMetadataContent(channel);
19
+ });
20
+ }
21
+ /** gets the EventPointer for a channel message or metadata event */
22
+ export function getChannelPointer(event) {
23
+ const tag = event.tags.find((t) => t[0] === "e" && t[1]);
24
+ if (!tag)
25
+ return undefined;
26
+ return tag[2] ? { id: tag[1], relays: [tag[2]] } : { id: tag[1] };
27
+ }
@@ -0,0 +1,47 @@
1
+ import { KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
2
+ import { ExternalIdentifiers, ExternalPointer } from "applesauce-core/helpers/external-id";
3
+ export declare const COMMENT_KIND = 1111;
4
+ /** Type for validated comment events */
5
+ export type CommentEvent = KnownEvent<typeof COMMENT_KIND>;
6
+ export type CommentEventPointer = {
7
+ type: "event";
8
+ id: string;
9
+ kind: number;
10
+ pubkey?: string;
11
+ relay?: string;
12
+ };
13
+ export type CommentAddressPointer = {
14
+ type: "address";
15
+ id?: string;
16
+ kind: number;
17
+ pubkey: string;
18
+ identifier: string;
19
+ relay?: string;
20
+ };
21
+ export type CommentExternalPointer<T extends keyof ExternalIdentifiers> = ExternalPointer<T> & {
22
+ type: "external";
23
+ };
24
+ export type CommentPointer = CommentEventPointer | CommentAddressPointer | CommentExternalPointer<keyof ExternalIdentifiers>;
25
+ export declare const CommentRootPointerSymbol: unique symbol;
26
+ export declare const CommentReplyPointerSymbol: unique symbol;
27
+ /** Gets the EventPointer from an array of tags */
28
+ export declare function getCommentEventPointer(tags: string[][], root?: boolean): CommentEventPointer | null;
29
+ /** Gets the AddressPointer from an array of tags */
30
+ export declare function getCommentAddressPointer(tags: string[][], root?: boolean): CommentAddressPointer | null;
31
+ /** Gets the ExternalPointer from an array of tags */
32
+ export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer<keyof ExternalIdentifiers> | null;
33
+ /** Returns the root pointer for a comment */
34
+ export declare function getCommentRootPointer(comment: CommentEvent): CommentPointer;
35
+ export declare function getCommentRootPointer(comment: NostrEvent): CommentPointer | null;
36
+ /** Returns the reply pointer for a comment */
37
+ export declare function getCommentReplyPointer(comment: NostrEvent): CommentPointer | null;
38
+ /** Checks if a pointer is a {@link CommentEventPointer} */
39
+ export declare function isCommentEventPointer(pointer: any): pointer is CommentEventPointer;
40
+ /** Checks if a pointer is a {@link CommentAddressPointer} */
41
+ export declare function isCommentAddressPointer(pointer: any): pointer is CommentAddressPointer;
42
+ /** Checks if a comment event is valid */
43
+ export declare function isValidComment(comment: NostrEvent): comment is CommentEvent;
44
+ /** Create a set fo tags for a single CommentPointer */
45
+ export declare function createCommentTagsFromCommentPointer(pointer: CommentPointer, root?: boolean): string[][];
46
+ /** Returns an array of NIP-22 tags for a kind 1111 comment event */
47
+ export declare function createCommentTagsForEvent(parent: NostrEvent, relayHint?: string): string[][];
@@ -0,0 +1,185 @@
1
+ import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
2
+ import { createReplaceableAddress, getTagValue, isAddressableKind, } from "applesauce-core/helpers/event";
3
+ import { getExternalPointerFromTag } from "applesauce-core/helpers/external-id";
4
+ import { getAddressPointerFromATag } from "applesauce-core/helpers/pointers";
5
+ import { isSafeRelayURL } from "applesauce-core/helpers/relays";
6
+ import { fillAndTrimTag } from "applesauce-core/helpers/tags";
7
+ export const COMMENT_KIND = 1111;
8
+ export const CommentRootPointerSymbol = Symbol.for("comment-root-pointer");
9
+ export const CommentReplyPointerSymbol = Symbol.for("comment-reply-pointer");
10
+ /** Gets the EventPointer from an array of tags */
11
+ export function getCommentEventPointer(tags, root = false) {
12
+ const eTag = tags.find((t) => t[0] === (root ? "E" : "e"));
13
+ const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
14
+ if (eTag) {
15
+ // Missing kind tag, return null
16
+ if (!kind)
17
+ return null;
18
+ // only the root pubkey can be gotten from the tags, since due to quotes and mentions there will be many "p" tags for replies
19
+ const rootPubkey = root ? tags.find((t) => t[0] === "P")?.[1] : undefined;
20
+ const pointer = {
21
+ type: "event",
22
+ id: eTag[1],
23
+ kind: parseInt(kind),
24
+ pubkey: eTag[3] || rootPubkey || undefined,
25
+ relay: eTag[2] && isSafeRelayURL(eTag[2]) ? eTag[2] : undefined,
26
+ };
27
+ return pointer;
28
+ }
29
+ return null;
30
+ }
31
+ /** Gets the AddressPointer from an array of tags */
32
+ export function getCommentAddressPointer(tags, root = false) {
33
+ const aTag = tags.find((t) => t[0] === (root ? "A" : "a"));
34
+ const eTag = tags.find((t) => t[0] === (root ? "E" : "e"));
35
+ const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
36
+ if (aTag) {
37
+ // Missing kind tag, return null
38
+ if (!kind)
39
+ return null;
40
+ const addressPointer = getAddressPointerFromATag(aTag);
41
+ const pointer = {
42
+ type: "address",
43
+ id: eTag?.[1],
44
+ pubkey: addressPointer.pubkey,
45
+ identifier: addressPointer.identifier,
46
+ kind: addressPointer.kind || parseInt(kind),
47
+ relay: addressPointer.relays?.[0] || eTag?.[2],
48
+ };
49
+ return pointer;
50
+ }
51
+ return null;
52
+ }
53
+ /** Gets the ExternalPointer from an array of tags */
54
+ export function getCommentExternalPointer(tags, root = false) {
55
+ const iTag = tags.find((t) => t[0] === (root ? "I" : "i"));
56
+ if (iTag) {
57
+ return {
58
+ type: "external",
59
+ ...getExternalPointerFromTag(iTag),
60
+ };
61
+ }
62
+ return null;
63
+ }
64
+ export function getCommentRootPointer(comment) {
65
+ if (comment.kind !== COMMENT_KIND)
66
+ return null;
67
+ return getOrComputeCachedValue(comment, CommentRootPointerSymbol, () => {
68
+ // check for address pointer first since it can also have E tags
69
+ const A = getCommentAddressPointer(comment.tags, true);
70
+ if (A)
71
+ return A;
72
+ const E = getCommentEventPointer(comment.tags, true);
73
+ if (E)
74
+ return E;
75
+ const I = getCommentExternalPointer(comment.tags, true);
76
+ if (I)
77
+ return I;
78
+ return null;
79
+ });
80
+ }
81
+ /** Returns the reply pointer for a comment */
82
+ export function getCommentReplyPointer(comment) {
83
+ if (comment.kind !== COMMENT_KIND)
84
+ return null;
85
+ return getOrComputeCachedValue(comment, CommentReplyPointerSymbol, () => {
86
+ // check for address pointer first since it can also have E tags
87
+ const A = getCommentAddressPointer(comment.tags, false);
88
+ if (A)
89
+ return A;
90
+ const E = getCommentEventPointer(comment.tags, false);
91
+ if (E)
92
+ return E;
93
+ const I = getCommentExternalPointer(comment.tags, false);
94
+ if (I)
95
+ return I;
96
+ return null;
97
+ });
98
+ }
99
+ /** Checks if a pointer is a {@link CommentEventPointer} */
100
+ export function isCommentEventPointer(pointer) {
101
+ return (Reflect.has(pointer, "id") &&
102
+ Reflect.has(pointer, "kind") &&
103
+ !Reflect.has(pointer, "identifier") &&
104
+ typeof pointer.kind === "number");
105
+ }
106
+ /** Checks if a pointer is a {@link CommentAddressPointer} */
107
+ export function isCommentAddressPointer(pointer) {
108
+ return (Reflect.has(pointer, "identifier") &&
109
+ Reflect.has(pointer, "pubkey") &&
110
+ Reflect.has(pointer, "kind") &&
111
+ typeof pointer.kind === "number");
112
+ }
113
+ /** Checks if a comment event is valid */
114
+ export function isValidComment(comment) {
115
+ return (comment.kind === COMMENT_KIND && getCommentRootPointer(comment) !== null && getCommentReplyPointer(comment) !== null);
116
+ }
117
+ /** Create a set fo tags for a single CommentPointer */
118
+ export function createCommentTagsFromCommentPointer(pointer, root = false) {
119
+ if (isCommentEventPointer(pointer)) {
120
+ // Event pointer
121
+ return [
122
+ fillAndTrimTag([root ? "E" : "e", pointer.id, pointer.relay, pointer.pubkey]),
123
+ [root ? "K" : "k", String(pointer.kind)],
124
+ pointer.pubkey ? fillAndTrimTag([root ? "P" : "p", pointer.pubkey]) : undefined,
125
+ ].filter((t) => !!t);
126
+ }
127
+ else if (isCommentAddressPointer(pointer)) {
128
+ // Address pointer
129
+ return [
130
+ fillAndTrimTag([
131
+ root ? "A" : "a",
132
+ createReplaceableAddress(pointer.kind, pointer.pubkey, pointer.identifier),
133
+ pointer.relay,
134
+ ]),
135
+ pointer.id ? fillAndTrimTag([root ? "E" : "e", pointer.id, pointer.relay, pointer.pubkey]) : undefined,
136
+ [root ? "K" : "k", String(pointer.kind)],
137
+ pointer.pubkey ? fillAndTrimTag([root ? "P" : "p", pointer.pubkey]) : undefined,
138
+ ].filter((t) => !!t);
139
+ }
140
+ else {
141
+ // External pointer
142
+ return [
143
+ [root ? "I" : "i", pointer.identifier],
144
+ [root ? "K" : "k", pointer.kind],
145
+ ];
146
+ }
147
+ throw new Error("Unknown comment pointer kind");
148
+ }
149
+ /** Returns an array of NIP-22 tags for a kind 1111 comment event */
150
+ export function createCommentTagsForEvent(parent, relayHint) {
151
+ const tags = [];
152
+ let parentPointer;
153
+ if (isAddressableKind(parent.kind)) {
154
+ const identifier = getTagValue(parent, "d");
155
+ if (!identifier)
156
+ throw new Error("Event missing identifier");
157
+ parentPointer = {
158
+ type: "address",
159
+ id: parent.id,
160
+ pubkey: parent.pubkey,
161
+ kind: parent.kind,
162
+ relay: relayHint,
163
+ identifier,
164
+ };
165
+ }
166
+ else {
167
+ parentPointer = { type: "event", id: parent.id, pubkey: parent.pubkey, kind: parent.kind, relay: relayHint };
168
+ }
169
+ // check if parent event is a comment
170
+ if (parent.kind === COMMENT_KIND) {
171
+ // comment is a reply to another comment
172
+ const pointer = getCommentRootPointer(parent);
173
+ if (!pointer)
174
+ throw new Error("Comment missing root pointer");
175
+ // recreate the root tags
176
+ tags.push(...createCommentTagsFromCommentPointer(pointer, true));
177
+ }
178
+ else {
179
+ // comment is root comment
180
+ tags.push(...createCommentTagsFromCommentPointer(parentPointer, true));
181
+ }
182
+ // add reply tags
183
+ tags.push(...createCommentTagsFromCommentPointer(parentPointer, false));
184
+ return tags;
185
+ }
@@ -0,0 +1,3 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ /** Returns the NIP-36 content-warning for an event. returns boolean if there is no "reason" */
3
+ export declare function getContentWarning(event: NostrEvent): string | boolean;
@@ -0,0 +1,8 @@
1
+ /** Returns the NIP-36 content-warning for an event. returns boolean if there is no "reason" */
2
+ export function getContentWarning(event) {
3
+ const tag = event.tags.find((t) => t[0] === "content-warning");
4
+ if (tag)
5
+ return tag[1] || true;
6
+ else
7
+ return false;
8
+ }
@@ -0,0 +1,21 @@
1
+ import { NostrEvent } from "applesauce-core/helpers/event";
2
+ export type Emoji = {
3
+ /** The emoji shortcode (without the ::) */
4
+ shortcode: string;
5
+ /** The URL to the emoji image */
6
+ url: string;
7
+ };
8
+ /** Gets an "emoji" tag that matches an emoji code */
9
+ export declare function getEmojiTag(tags: {
10
+ tags: string[][];
11
+ } | string[][], code: string): ["emoji", string, string] | undefined;
12
+ /** Gets an emoji for a shortcode from an array of tags or event */
13
+ export declare function getEmojiFromTags(event: {
14
+ tags: string[][];
15
+ } | string[][], code: string): Emoji | undefined;
16
+ /** Returns the name of a NIP-30 emoji pack */
17
+ export declare function getPackName(pack: NostrEvent): string | undefined;
18
+ /** Returns an array of emojis from a NIP-30 emoji pack */
19
+ export declare function getEmojis(pack: NostrEvent): Emoji[];
20
+ /** Returns the custom emoji for a reaction event */
21
+ export declare function getReactionEmoji(event: NostrEvent): Emoji | undefined;