Bookmarks
Bookmarks let users save notes and articles to come back to later. Each user has one bookmark list (kind 10003) and can keep any number of named bookmark sets (kind 30003), with entries that can be public or hidden.
Reading bookmarks
user.bookmarks$ loads the user's bookmark list from their outboxes and casts it to BookmarksList. notes$ and articles$ resolve the bookmarked events as Note and Article casts.
const bookmarks = use$(user.bookmarks$);
const notes = use$(bookmarks?.notes$);
const articles = use$(bookmarks?.articles$);
bookmarks?.bookmarks; // (EventPointer | AddressPointer)[]notes and articles hold the raw pointers when you want to load or render them yourself. Events that aren't in the store yet are left out until they load.
Example: Bookmarks Manager
Unlocking hidden bookmarks
Hidden bookmarks stay encrypted until the user's signer decrypts them. hidden$, hiddenNotes$, and hiddenArticles$ emit undefined while locked and update once unlocked.
if (bookmarks.hasHidden && !bookmarks.unlocked) await bookmarks.unlock(signer);
const hiddenNotes = use$(bookmarks.hiddenNotes$);Use encrypted content caching to keep the decrypted entries across reloads.
Bookmark sets
BookmarksSet has the same API as BookmarksList. Load a set by its d identifier.
const set = use$(
() => eventStore.replaceable({ kind: 30003, pubkey, identifier }).pipe(castEventStream(BookmarksSet, eventStore)),
[pubkey, identifier],
);Adding and removing bookmarks
BookmarkEvent and UnbookmarkEvent take an event or pointer, an optional set, and a hidden flag. Leave the set undefined to use the bookmark list; pass a d identifier or set event to target a set.
await actions.run(BookmarkEvent, note);
await actions.run(BookmarkEvent, article, "reading-list", true); // hidden, in a set
await actions.run(UnbookmarkEvent, note);CreateBookmarkList(events?) creates the list and throws if one exists. CreateBookmarkSet(title, description, { image, public, hidden }) creates a new set.
Building bookmark events
BookmarkListFactory and BookmarkSetFactory from applesauce-common/factories build the events directly. Both have bookmarkEvent(), bookmarkUrl(), and bookmarkHashtag(), each with an unbookmark counterpart and a hidden flag.
const signed = await BookmarkListFactory.modify(list.event).bookmarkEvent(note).sign(signer);The casts only read note and article bookmarks, so read URL and hashtag entries with getListTags(event) from applesauce-common/helpers.
Helpers
getBookmarks(event)returns the public bookmark pointersgetHiddenBookmarks(event)returns the hidden pointers, orundefinedwhile lockedunlockHiddenBookmarks(event, signer)decrypts hidden bookmarks and notifies the storeisValidBookmarkList(event)andisValidBookmarkSet(event)check the kind
Best Practices
- Use
BookmarkEventandUnbookmarkEventinstead of rebuilding the list, so bookmarks added by other clients are kept - Check
hasHiddenbefore showing an unlock button, since most lists have no hidden entries - Load bookmarked events with an event loader so
notes$andarticles$fill in