applesauce-common 0.0.0-next-20251209200210 → 0.0.0-next-20251231055351
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -4
- package/dist/blueprints/__register__.d.ts +7 -0
- package/dist/blueprints/__register__.js +8 -0
- package/dist/blueprints/comment.d.ts +3 -2
- package/dist/blueprints/group-mangement.d.ts +25 -0
- package/dist/blueprints/group-mangement.js +40 -0
- package/dist/blueprints/index.d.ts +1 -0
- package/dist/blueprints/index.js +1 -0
- package/dist/blueprints/torrent.d.ts +7 -0
- package/dist/blueprints/torrent.js +5 -1
- package/dist/casts/article.d.ts +19 -0
- package/dist/casts/article.js +47 -0
- package/dist/casts/bookmarks.d.ts +35 -0
- package/dist/casts/bookmarks.js +91 -0
- package/dist/casts/cast.d.ts +30 -0
- package/dist/casts/cast.js +67 -0
- package/dist/casts/comment.d.ts +18 -0
- package/dist/casts/comment.js +54 -0
- package/dist/casts/groups.d.ts +19 -0
- package/dist/casts/groups.js +43 -0
- package/dist/casts/index.d.ts +18 -0
- package/dist/casts/index.js +18 -0
- package/dist/casts/mutes.d.ts +23 -0
- package/dist/casts/mutes.js +54 -0
- package/dist/casts/note.d.ts +25 -0
- package/dist/casts/note.js +76 -0
- package/dist/casts/profile.d.ts +24 -0
- package/dist/casts/profile.js +52 -0
- package/dist/casts/reaction.d.ts +17 -0
- package/dist/casts/reaction.js +46 -0
- package/dist/casts/relay-discovery.d.ts +29 -0
- package/dist/casts/relay-discovery.js +54 -0
- package/dist/casts/relay-lists.d.ts +33 -0
- package/dist/casts/relay-lists.js +72 -0
- package/dist/casts/relay-monitor.d.ts +21 -0
- package/dist/casts/relay-monitor.js +41 -0
- package/dist/casts/report.d.ts +31 -0
- package/dist/casts/report.js +74 -0
- package/dist/casts/share.d.ts +15 -0
- package/dist/casts/share.js +34 -0
- package/dist/casts/stream.d.ts +43 -0
- package/dist/casts/stream.js +116 -0
- package/dist/casts/torrent.d.ts +31 -0
- package/dist/casts/torrent.js +62 -0
- package/dist/casts/user.d.ts +40 -0
- package/dist/casts/user.js +181 -0
- package/dist/casts/zap.d.ts +17 -0
- package/dist/casts/zap.js +47 -0
- package/dist/helpers/bookmark.d.ts +18 -17
- package/dist/helpers/bookmark.js +36 -49
- package/dist/helpers/calendar-event.d.ts +7 -1
- package/dist/helpers/calendar-event.js +8 -10
- package/dist/helpers/channels.d.ts +1 -1
- package/dist/helpers/channels.js +5 -8
- package/dist/helpers/comment.d.ts +3 -1
- package/dist/helpers/comment.js +12 -2
- package/dist/helpers/encrypted-content-cache.js +23 -25
- package/dist/helpers/external-id.d.ts +32 -0
- package/dist/helpers/external-id.js +85 -0
- package/dist/helpers/file-metadata.d.ts +1 -4
- package/dist/helpers/file-metadata.js +1 -4
- package/dist/helpers/gift-wrap.js +11 -5
- package/dist/helpers/groups.d.ts +129 -7
- package/dist/helpers/groups.js +317 -15
- package/dist/helpers/index.d.ts +1 -1
- package/dist/helpers/index.js +1 -1
- package/dist/helpers/lists.d.ts +0 -1
- package/dist/helpers/lists.js +4 -5
- package/dist/helpers/mute.d.ts +14 -11
- package/dist/helpers/mute.js +9 -4
- package/dist/helpers/relay-list.d.ts +14 -0
- package/dist/helpers/relay-list.js +18 -0
- package/dist/helpers/reports.d.ts +4 -1
- package/dist/helpers/reports.js +14 -10
- package/dist/helpers/stream-chat.d.ts +4 -1
- package/dist/helpers/stream-chat.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/__register__.d.ts +5 -0
- package/dist/models/__register__.js +6 -0
- package/dist/models/blossom.d.ts +2 -2
- package/dist/models/blossom.js +1 -1
- package/dist/models/bookmarks.d.ts +3 -5
- package/dist/models/bookmarks.js +2 -10
- package/dist/models/channels.js +3 -9
- package/dist/models/comments.d.ts +3 -2
- package/dist/models/comments.js +19 -1
- package/dist/models/index.d.ts +3 -1
- package/dist/models/index.js +4 -1
- package/dist/models/mutes.d.ts +5 -5
- package/dist/models/{relays.js → relay-lists.js} +2 -1
- package/dist/models/shares.d.ts +3 -0
- package/dist/models/shares.js +5 -0
- package/dist/models/thread.js +30 -24
- package/dist/observable/cast-stream.d.ts +8 -0
- package/dist/observable/cast-stream.js +29 -0
- package/dist/observable/chainable.d.ts +50 -0
- package/dist/observable/chainable.js +79 -0
- package/dist/observable/index.d.ts +2 -0
- package/dist/observable/index.js +2 -0
- package/dist/operations/comment.d.ts +3 -2
- package/dist/operations/comment.js +19 -5
- package/dist/operations/group.d.ts +14 -1
- package/dist/operations/group.js +42 -4
- package/dist/operations/index.d.ts +1 -1
- package/dist/operations/index.js +1 -1
- package/dist/operations/tag/bookmarks.d.ts +3 -2
- package/dist/operations/tag/bookmarks.js +34 -14
- package/dist/operations/torrent.d.ts +2 -0
- package/dist/operations/torrent.js +4 -0
- package/dist/register.d.ts +2 -11
- package/dist/register.js +2 -11
- package/package.json +12 -2
- package/dist/helpers/mailboxes.d.ts +0 -7
- package/dist/helpers/mailboxes.js +0 -49
- /package/dist/models/{relays.d.ts → relay-lists.d.ts} +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { of } from "rxjs";
|
|
2
|
+
import { getZapAddressPointer, getZapAmount, getZapEventPointer, getZapPayment, getZapPreimage, getZapRecipient, getZapRequest, getZapSender, isValidZap, } from "../helpers/zap.js";
|
|
3
|
+
import { EventCast } from "./cast.js";
|
|
4
|
+
import { castUser } from "./user.js";
|
|
5
|
+
// NOTE: extending BaseCast since there is no need for author$ or comments$
|
|
6
|
+
/** Cast a kind 9735 event to a Zap */
|
|
7
|
+
export class Zap extends EventCast {
|
|
8
|
+
constructor(event, store) {
|
|
9
|
+
if (!isValidZap(event))
|
|
10
|
+
throw new Error("Invalid zap");
|
|
11
|
+
super(event, store);
|
|
12
|
+
}
|
|
13
|
+
get sender() {
|
|
14
|
+
return castUser(getZapSender(this.event), this.store);
|
|
15
|
+
}
|
|
16
|
+
get recipient() {
|
|
17
|
+
return castUser(getZapRecipient(this.event), this.store);
|
|
18
|
+
}
|
|
19
|
+
get payment() {
|
|
20
|
+
return getZapPayment(this.event);
|
|
21
|
+
}
|
|
22
|
+
get amount() {
|
|
23
|
+
return getZapAmount(this.event);
|
|
24
|
+
}
|
|
25
|
+
get preimage() {
|
|
26
|
+
return getZapPreimage(this.event);
|
|
27
|
+
}
|
|
28
|
+
get request() {
|
|
29
|
+
return getZapRequest(this.event);
|
|
30
|
+
}
|
|
31
|
+
get addressPointer() {
|
|
32
|
+
return getZapAddressPointer(this.event);
|
|
33
|
+
}
|
|
34
|
+
get eventPointer() {
|
|
35
|
+
return getZapEventPointer(this.event);
|
|
36
|
+
}
|
|
37
|
+
/** An observable of the zapped event */
|
|
38
|
+
get event$() {
|
|
39
|
+
return this.$$ref("event$", (store) => {
|
|
40
|
+
if (this.addressPointer)
|
|
41
|
+
return store.replaceable(this.addressPointer);
|
|
42
|
+
if (this.eventPointer)
|
|
43
|
+
return store.event(this.eventPointer.id);
|
|
44
|
+
return of(undefined);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
1
|
+
import { kinds, KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
|
|
2
2
|
import { HiddenContentSigner } from "applesauce-core/helpers/hidden-content";
|
|
3
3
|
import { AddressPointer, EventPointer } from "applesauce-core/helpers/pointers";
|
|
4
|
+
/** Type for a validated bookmark list event */
|
|
5
|
+
export type BookmarkListEvent = KnownEvent<kinds.BookmarkList>;
|
|
6
|
+
/** Type for a validated bookmark set event */
|
|
7
|
+
export type BookmarkSetEvent = KnownEvent<kinds.Bookmarksets>;
|
|
8
|
+
/** Validates that an event is a valid bookmark list (kind 10000) */
|
|
9
|
+
export declare function isValidBookmarkList(event: NostrEvent): event is BookmarkListEvent;
|
|
10
|
+
/** Validates that an event is a valid bookmark set (kind 30003) */
|
|
11
|
+
export declare function isValidBookmarkSet(event: NostrEvent): event is BookmarkSetEvent;
|
|
4
12
|
export declare const BookmarkPublicSymbol: unique symbol;
|
|
5
13
|
export declare const BookmarkHiddenSymbol: unique symbol;
|
|
14
|
+
export type BookmarkPointer = EventPointer | AddressPointer;
|
|
6
15
|
/** Type for unlocked bookmarks events */
|
|
7
16
|
export type UnlockedBookmarks = {
|
|
8
|
-
[BookmarkHiddenSymbol]:
|
|
9
|
-
};
|
|
10
|
-
export type Bookmarks = {
|
|
11
|
-
notes: EventPointer[];
|
|
12
|
-
articles: AddressPointer[];
|
|
13
|
-
hashtags: string[];
|
|
14
|
-
urls: string[];
|
|
17
|
+
[BookmarkHiddenSymbol]: BookmarkPointer[];
|
|
15
18
|
};
|
|
16
19
|
/** Parses an array of tags into a {@link Bookmarks} object */
|
|
17
|
-
export declare function parseBookmarkTags(tags: string[][]):
|
|
20
|
+
export declare function parseBookmarkTags(tags: string[][]): BookmarkPointer[];
|
|
18
21
|
/** Merges any number of {@link Bookmarks} objects */
|
|
19
|
-
export declare function mergeBookmarks(...bookmarks: (
|
|
20
|
-
/** Returns
|
|
21
|
-
export declare function getBookmarks(bookmark: NostrEvent):
|
|
22
|
-
/** Returns the public bookmarks of the event */
|
|
23
|
-
export declare function getPublicBookmarks(bookmark: NostrEvent): Bookmarks;
|
|
22
|
+
export declare function mergeBookmarks(...bookmarks: (BookmarkPointer[] | undefined)[]): BookmarkPointer[];
|
|
23
|
+
/** Returns the bookmarks of the event */
|
|
24
|
+
export declare function getBookmarks(bookmark: NostrEvent): BookmarkPointer[];
|
|
24
25
|
/** Checks if the hidden bookmarks are unlocked */
|
|
25
26
|
export declare function isHiddenBookmarksUnlocked<T extends NostrEvent>(bookmark: T): bookmark is T & UnlockedBookmarks;
|
|
26
27
|
/** Returns the bookmarks of the event if its unlocked */
|
|
27
|
-
export declare function getHiddenBookmarks<T extends NostrEvent & UnlockedBookmarks>(bookmark: T):
|
|
28
|
-
export declare function getHiddenBookmarks<T extends NostrEvent>(bookmark: T):
|
|
28
|
+
export declare function getHiddenBookmarks<T extends NostrEvent & UnlockedBookmarks>(bookmark: T): BookmarkPointer[];
|
|
29
|
+
export declare function getHiddenBookmarks<T extends NostrEvent>(bookmark: T): BookmarkPointer[] | undefined;
|
|
29
30
|
/** Unlocks the hidden bookmarks on a bookmarks event */
|
|
30
|
-
export declare function unlockHiddenBookmarks(bookmark: NostrEvent, signer: HiddenContentSigner): Promise<
|
|
31
|
+
export declare function unlockHiddenBookmarks(bookmark: NostrEvent, signer: HiddenContentSigner): Promise<BookmarkPointer[]>;
|
package/dist/helpers/bookmark.js
CHANGED
|
@@ -1,78 +1,65 @@
|
|
|
1
|
-
import { getOrComputeCachedValue, notifyEventUpdate } from "applesauce-core/helpers";
|
|
1
|
+
import { getOrComputeCachedValue, isATag, isETag, notifyEventUpdate, processTags } 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, getReplaceableAddressFromPointer,
|
|
4
|
+
import { getAddressPointerFromATag, getEventPointerFromETag, getReplaceableAddressFromPointer, isAddressPointer, isEventPointer, mergeAddressPointers, mergeEventPointers, } from "applesauce-core/helpers/pointers";
|
|
5
|
+
/** Validates that an event is a valid bookmark list (kind 10000) */
|
|
6
|
+
export function isValidBookmarkList(event) {
|
|
7
|
+
return event.kind === kinds.BookmarkList;
|
|
8
|
+
}
|
|
9
|
+
/** Validates that an event is a valid bookmark set (kind 30003) */
|
|
10
|
+
export function isValidBookmarkSet(event) {
|
|
11
|
+
return event.kind === kinds.Bookmarksets;
|
|
12
|
+
}
|
|
5
13
|
export const BookmarkPublicSymbol = Symbol.for("bookmark-public");
|
|
6
14
|
export const BookmarkHiddenSymbol = Symbol.for("bookmark-hidden");
|
|
7
15
|
/** Parses an array of tags into a {@link Bookmarks} object */
|
|
8
16
|
export function parseBookmarkTags(tags) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
return processTags(tags, (t) => {
|
|
18
|
+
if (isETag(t))
|
|
19
|
+
return getEventPointerFromETag(t) ?? undefined;
|
|
20
|
+
if (isATag(t)) {
|
|
21
|
+
const pointer = getAddressPointerFromATag(t) ?? undefined;
|
|
22
|
+
// Ensure the address pointer is a long form article
|
|
23
|
+
if (pointer?.kind !== kinds.LongFormArticle)
|
|
24
|
+
return undefined;
|
|
25
|
+
return pointer;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
});
|
|
21
29
|
}
|
|
22
30
|
/** Merges any number of {@link Bookmarks} objects */
|
|
23
31
|
export function mergeBookmarks(...bookmarks) {
|
|
24
32
|
const notes = new Map();
|
|
25
33
|
const articles = new Map();
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!bookmark)
|
|
30
|
-
continue;
|
|
31
|
-
for (const note of bookmark.notes) {
|
|
32
|
-
const existing = notes.get(note.id);
|
|
34
|
+
for (const pointer of bookmarks.flat()) {
|
|
35
|
+
if (isEventPointer(pointer)) {
|
|
36
|
+
const existing = notes.get(pointer.id);
|
|
33
37
|
if (existing)
|
|
34
|
-
notes.set(
|
|
38
|
+
notes.set(pointer.id, mergeEventPointers(existing, pointer));
|
|
35
39
|
else
|
|
36
|
-
notes.set(
|
|
40
|
+
notes.set(pointer.id, pointer);
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const existing = articles.get(
|
|
42
|
+
else if (isAddressPointer(pointer)) {
|
|
43
|
+
const address = getReplaceableAddressFromPointer(pointer);
|
|
44
|
+
const existing = articles.get(address);
|
|
41
45
|
if (existing)
|
|
42
|
-
articles.set(
|
|
46
|
+
articles.set(address, mergeAddressPointers(existing, pointer));
|
|
43
47
|
else
|
|
44
|
-
articles.set(
|
|
48
|
+
articles.set(address, pointer);
|
|
45
49
|
}
|
|
46
|
-
for (const hashtag of bookmark.hashtags)
|
|
47
|
-
hashtags.add(hashtag);
|
|
48
|
-
for (const url of bookmark.urls)
|
|
49
|
-
urls.add(url);
|
|
50
50
|
}
|
|
51
|
-
return
|
|
52
|
-
notes: Array.from(notes.values()),
|
|
53
|
-
articles: Array.from(articles.values()),
|
|
54
|
-
hashtags: Array.from(hashtags),
|
|
55
|
-
urls: Array.from(urls),
|
|
56
|
-
};
|
|
51
|
+
return [...notes.values(), ...articles.values()];
|
|
57
52
|
}
|
|
58
|
-
/** Returns
|
|
53
|
+
/** Returns the bookmarks of the event */
|
|
59
54
|
export function getBookmarks(bookmark) {
|
|
60
|
-
const hidden = getHiddenBookmarks(bookmark);
|
|
61
|
-
if (hidden)
|
|
62
|
-
return mergeBookmarks(hidden, getPublicBookmarks(bookmark));
|
|
63
|
-
else
|
|
64
|
-
return getPublicBookmarks(bookmark);
|
|
65
|
-
}
|
|
66
|
-
/** Returns the public bookmarks of the event */
|
|
67
|
-
export function getPublicBookmarks(bookmark) {
|
|
68
55
|
return getOrComputeCachedValue(bookmark, BookmarkPublicSymbol, () => parseBookmarkTags(bookmark.tags));
|
|
69
56
|
}
|
|
70
57
|
/** Checks if the hidden bookmarks are unlocked */
|
|
71
58
|
export function isHiddenBookmarksUnlocked(bookmark) {
|
|
72
|
-
return isHiddenTagsUnlocked(bookmark) &&
|
|
59
|
+
return (isHiddenTagsUnlocked(bookmark) && (BookmarkHiddenSymbol in bookmark || getHiddenBookmarks(bookmark) !== undefined));
|
|
73
60
|
}
|
|
74
61
|
export function getHiddenBookmarks(bookmark) {
|
|
75
|
-
if (
|
|
62
|
+
if (BookmarkHiddenSymbol in bookmark)
|
|
76
63
|
return bookmark[BookmarkHiddenSymbol];
|
|
77
64
|
//get hidden tags
|
|
78
65
|
const tags = getHiddenTags(bookmark);
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
1
|
+
import { KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
|
|
2
2
|
import { ProfilePointer } from "applesauce-core/helpers/pointers";
|
|
3
3
|
import { NameValueTag } from "applesauce-core/helpers/tags";
|
|
4
4
|
export declare const DATE_BASED_CALENDAR_EVENT_KIND = 31922;
|
|
5
5
|
export declare const TIME_BASED_CALENDAR_EVENT_KIND = 31923;
|
|
6
|
+
export type DateBasedCalendarEvent = KnownEvent<typeof DATE_BASED_CALENDAR_EVENT_KIND>;
|
|
7
|
+
export type TimeBasedCalendarEvent = KnownEvent<typeof TIME_BASED_CALENDAR_EVENT_KIND>;
|
|
8
|
+
/** Checks if an event is a date-based calendar event */
|
|
9
|
+
export declare function isValidDateBasedCalendarEvent(event: NostrEvent): event is DateBasedCalendarEvent;
|
|
10
|
+
/** Checks if an event is a time-based calendar event */
|
|
11
|
+
export declare function isValidTimeBasedCalendarEvent(event: NostrEvent): event is TimeBasedCalendarEvent;
|
|
6
12
|
export type CalendarEventParticipant = ProfilePointer & {
|
|
7
13
|
role?: string;
|
|
8
14
|
};
|
|
@@ -6,6 +6,14 @@ import { fillAndTrimTag, isPTag, isRTag, isTTag } from "applesauce-core/helpers/
|
|
|
6
6
|
// NIP-52 Calendar Event Kinds
|
|
7
7
|
export const DATE_BASED_CALENDAR_EVENT_KIND = 31922;
|
|
8
8
|
export const TIME_BASED_CALENDAR_EVENT_KIND = 31923;
|
|
9
|
+
/** Checks if an event is a date-based calendar event */
|
|
10
|
+
export function isValidDateBasedCalendarEvent(event) {
|
|
11
|
+
return event.kind === DATE_BASED_CALENDAR_EVENT_KIND;
|
|
12
|
+
}
|
|
13
|
+
/** Checks if an event is a time-based calendar event */
|
|
14
|
+
export function isValidTimeBasedCalendarEvent(event) {
|
|
15
|
+
return event.kind === TIME_BASED_CALENDAR_EVENT_KIND;
|
|
16
|
+
}
|
|
9
17
|
// Cache symbols for complex operations only
|
|
10
18
|
export const CalendarEventLocationsSymbol = Symbol.for("calendar-event-locations");
|
|
11
19
|
export const CalendarEventParticipantsSymbol = Symbol.for("calendar-event-participants");
|
|
@@ -62,16 +70,12 @@ export function getCalendarEventEnd(event) {
|
|
|
62
70
|
}
|
|
63
71
|
/** Gets all locations from a calendar event */
|
|
64
72
|
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
73
|
return getOrComputeCachedValue(event, CalendarEventLocationsSymbol, () => {
|
|
68
74
|
return event.tags.filter((t) => t[0] === "location" && t[1]).map((t) => t[1]);
|
|
69
75
|
});
|
|
70
76
|
}
|
|
71
77
|
/** Gets the geohash of a calendar event */
|
|
72
78
|
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
79
|
return getOrComputeCachedValue(event, CalendarEventGeohashSymbol, () => {
|
|
76
80
|
let hash = undefined;
|
|
77
81
|
for (const tag of event.tags) {
|
|
@@ -83,8 +87,6 @@ export function getCalendarEventGeohash(event) {
|
|
|
83
87
|
}
|
|
84
88
|
/** Gets all participants from a calendar event */
|
|
85
89
|
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
90
|
return getOrComputeCachedValue(event, CalendarEventParticipantsSymbol, () => {
|
|
89
91
|
return event.tags
|
|
90
92
|
.filter(isPTag)
|
|
@@ -102,16 +104,12 @@ export function getCalendarEventParticipants(event) {
|
|
|
102
104
|
}
|
|
103
105
|
/** Gets all hashtags from a calendar event */
|
|
104
106
|
export function getCalendarEventHashtags(event) {
|
|
105
|
-
if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
|
|
106
|
-
throw new Error("Event is not a date-based or time-based calendar event");
|
|
107
107
|
return getOrComputeCachedValue(event, CalendarEventHashtagsSymbol, () => {
|
|
108
108
|
return event.tags.filter(isTTag).map((t) => t[1]);
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
/** Gets all references from a calendar event */
|
|
112
112
|
export function getCalendarEventReferences(event) {
|
|
113
|
-
if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
|
|
114
|
-
throw new Error("Event is not a date-based or time-based calendar event");
|
|
115
113
|
return getOrComputeCachedValue(event, CalendarEventReferencesSymbol, () => {
|
|
116
114
|
return event.tags.filter(isRTag).map((t) => t[1]);
|
|
117
115
|
});
|
|
@@ -8,6 +8,6 @@ export type ChannelMetadataContent = {
|
|
|
8
8
|
relays?: string[];
|
|
9
9
|
};
|
|
10
10
|
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
11
|
-
export declare function getChannelMetadataContent(channel: NostrEvent): ChannelMetadataContent;
|
|
11
|
+
export declare function getChannelMetadataContent(channel: NostrEvent): ChannelMetadataContent | null;
|
|
12
12
|
/** gets the EventPointer for a channel message or metadata event */
|
|
13
13
|
export declare function getChannelPointer(event: NostrEvent): EventPointer | undefined;
|
package/dist/helpers/channels.js
CHANGED
|
@@ -2,14 +2,11 @@ import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
|
|
|
2
2
|
export const ChannelMetadataSymbol = Symbol.for("channel-metadata");
|
|
3
3
|
function parseChannelMetadataContent(channel) {
|
|
4
4
|
const metadata = JSON.parse(channel.content);
|
|
5
|
-
if (metadata.name === undefined
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
throw new Error("Missing picture");
|
|
11
|
-
if (metadata.relays && !Array.isArray(metadata.relays))
|
|
12
|
-
throw new Error("Invalid relays");
|
|
5
|
+
if (metadata.name === undefined ||
|
|
6
|
+
metadata.about === undefined ||
|
|
7
|
+
metadata.picture === undefined ||
|
|
8
|
+
(metadata.relays && !Array.isArray(metadata.relays)))
|
|
9
|
+
return null;
|
|
13
10
|
return metadata;
|
|
14
11
|
}
|
|
15
12
|
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
-
import { ExternalIdentifiers, ExternalPointer } from "
|
|
2
|
+
import { ExternalIdentifiers, ExternalPointer } from "./external-id.js";
|
|
3
3
|
export declare const COMMENT_KIND = 1111;
|
|
4
4
|
/** Type for validated comment events */
|
|
5
5
|
export type CommentEvent = KnownEvent<typeof COMMENT_KIND>;
|
|
@@ -39,6 +39,8 @@ export declare function getCommentReplyPointer(comment: NostrEvent): CommentPoin
|
|
|
39
39
|
export declare function isCommentEventPointer(pointer: any): pointer is CommentEventPointer;
|
|
40
40
|
/** Checks if a pointer is a {@link CommentAddressPointer} */
|
|
41
41
|
export declare function isCommentAddressPointer(pointer: any): pointer is CommentAddressPointer;
|
|
42
|
+
/** Checks if a pointer is a {@link CommentExternalPointer} */
|
|
43
|
+
export declare function isCommentExternalPointer(pointer: any): pointer is CommentExternalPointer<keyof ExternalIdentifiers>;
|
|
42
44
|
/** Checks if a comment event is valid */
|
|
43
45
|
export declare function isValidComment(comment: NostrEvent): comment is CommentEvent;
|
|
44
46
|
/** Create a set fo tags for a single CommentPointer */
|
package/dist/helpers/comment.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
|
|
2
2
|
import { createReplaceableAddress, getTagValue, isAddressableKind, } from "applesauce-core/helpers/event";
|
|
3
|
-
import { getExternalPointerFromTag } from "applesauce-core/helpers/external-id";
|
|
4
3
|
import { getAddressPointerFromATag } from "applesauce-core/helpers/pointers";
|
|
5
4
|
import { isSafeRelayURL } from "applesauce-core/helpers/relays";
|
|
6
5
|
import { fillAndTrimTag } from "applesauce-core/helpers/tags";
|
|
6
|
+
import { getExternalPointerFromTag } from "./external-id.js";
|
|
7
7
|
export const COMMENT_KIND = 1111;
|
|
8
8
|
export const CommentRootPointerSymbol = Symbol.for("comment-root-pointer");
|
|
9
9
|
export const CommentReplyPointerSymbol = Symbol.for("comment-reply-pointer");
|
|
@@ -56,9 +56,12 @@ export function getCommentAddressPointer(tags, root = false) {
|
|
|
56
56
|
export function getCommentExternalPointer(tags, root = false) {
|
|
57
57
|
const iTag = tags.find((t) => t[0] === (root ? "I" : "i"));
|
|
58
58
|
if (iTag) {
|
|
59
|
+
const pointer = getExternalPointerFromTag(iTag);
|
|
60
|
+
if (!pointer)
|
|
61
|
+
return null;
|
|
59
62
|
return {
|
|
60
63
|
type: "external",
|
|
61
|
-
...
|
|
64
|
+
...pointer,
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
return null;
|
|
@@ -112,6 +115,13 @@ export function isCommentAddressPointer(pointer) {
|
|
|
112
115
|
Reflect.has(pointer, "kind") &&
|
|
113
116
|
typeof pointer.kind === "number");
|
|
114
117
|
}
|
|
118
|
+
/** Checks if a pointer is a {@link CommentExternalPointer} */
|
|
119
|
+
export function isCommentExternalPointer(pointer) {
|
|
120
|
+
return (pointer?.type === "external" &&
|
|
121
|
+
Reflect.has(pointer, "kind") &&
|
|
122
|
+
Reflect.has(pointer, "identifier") &&
|
|
123
|
+
typeof pointer.kind === "string");
|
|
124
|
+
}
|
|
115
125
|
/** Checks if a comment event is valid */
|
|
116
126
|
export function isValidComment(comment) {
|
|
117
127
|
return (comment.kind === COMMENT_KIND && getCommentRootPointer(comment) !== null && getCommentReplyPointer(comment) !== null);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { logger } from "applesauce-core";
|
|
2
2
|
import { canHaveEncryptedContent, getEncryptedContent, isEncryptedContentUnlocked, setEncryptedContentCache, } from "applesauce-core/helpers/encrypted-content";
|
|
3
3
|
import { kinds, notifyEventUpdate } from "applesauce-core/helpers/event";
|
|
4
|
-
import { catchError, combineLatest, distinct, EMPTY, filter, isObservable, map, merge, mergeMap, of, switchMap, } from "rxjs";
|
|
5
|
-
import { getGiftWrapSeal, getSealGiftWrap, getSealRumor } from "./gift-wrap.js";
|
|
4
|
+
import { catchError, combineLatest, combineLatestWith, distinct, EMPTY, filter, isObservable, map, merge, mergeMap, of, switchMap, } from "rxjs";
|
|
5
|
+
import { getGiftWrapSeal, getSealGiftWrap, getSealRumor, isGiftWrapUnlocked } from "./gift-wrap.js";
|
|
6
6
|
/** A symbol that is used to mark encrypted content as being from a cache */
|
|
7
7
|
export const EncryptedContentFromCacheSymbol = Symbol.for("encrypted-content-from-cache");
|
|
8
8
|
/** Marks the encrypted content as being from a cache */
|
|
@@ -32,15 +32,20 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
32
32
|
.pipe(
|
|
33
33
|
// Look for events that support encrypted content and are locked
|
|
34
34
|
filter((e) => canHaveEncryptedContent(e.kind) && isEncryptedContentUnlocked(e) === false),
|
|
35
|
+
// Get the storage
|
|
36
|
+
combineLatestWith(storage$),
|
|
35
37
|
// Get the encrypted content from storage
|
|
36
|
-
mergeMap((event) =>
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
mergeMap(([event, storage]) =>
|
|
39
|
+
// Get content from storage
|
|
40
|
+
combineLatest([
|
|
41
|
+
of(event),
|
|
42
|
+
getItem(storage, event).catch((error) => {
|
|
43
|
+
log(`Failed to restore encrypted content for ${event.id}`, error);
|
|
44
|
+
return of(null);
|
|
45
|
+
}),
|
|
46
|
+
])))
|
|
42
47
|
.subscribe(async ([event, content]) => {
|
|
43
|
-
if (
|
|
48
|
+
if (typeof content !== "string")
|
|
44
49
|
return;
|
|
45
50
|
// Restore the encrypted content and set it as from a cache
|
|
46
51
|
markEncryptedContentFromCache(event);
|
|
@@ -79,14 +84,16 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
79
84
|
log(`Restored encrypted content for ${seal.id}`);
|
|
80
85
|
});
|
|
81
86
|
// Persist encrypted content when it is updated or inserted
|
|
82
|
-
const persist =
|
|
87
|
+
const persist = merge(eventStore.update$, eventStore.insert$)
|
|
83
88
|
.pipe(
|
|
84
89
|
// Look for events that support encrypted content and are unlocked and not from the cache
|
|
85
|
-
filter((
|
|
90
|
+
filter((event) => canHaveEncryptedContent(event.kind) &&
|
|
86
91
|
isEncryptedContentUnlocked(event) &&
|
|
87
|
-
|
|
92
|
+
isEncryptedContentFromCache(event) === false),
|
|
88
93
|
// Only persist the encrypted content once
|
|
89
|
-
distinct((
|
|
94
|
+
distinct((event) => event.id),
|
|
95
|
+
// get the storage
|
|
96
|
+
combineLatestWith(storage$))
|
|
90
97
|
.subscribe(async ([event, storage]) => {
|
|
91
98
|
try {
|
|
92
99
|
const content = getEncryptedContent(event);
|
|
@@ -102,18 +109,9 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
102
109
|
});
|
|
103
110
|
// Persist seals when the gift warp is unlocked or inserted unlocked
|
|
104
111
|
// This relies on the gift wrap event being updated when a seal is unlocked
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
filter(([event]) => event.kind === kinds.GiftWrap && isEncryptedContentUnlocked(event)),
|
|
109
|
-
// Get the seal event
|
|
110
|
-
map(([gift, storage]) => [getGiftWrapSeal(gift), storage]),
|
|
111
|
-
// Make sure the seal is defined
|
|
112
|
-
filter(([seal]) => seal !== undefined),
|
|
113
|
-
// Make sure seal is unlocked and not from cache
|
|
114
|
-
filter(([seal]) => isEncryptedContentUnlocked(seal) && !isEncryptedContentFromCache(seal)),
|
|
115
|
-
// Only persist the seal once
|
|
116
|
-
distinct(([seal]) => seal.id))
|
|
112
|
+
const unlockedSeals$ = merge(eventStore.update$, eventStore.insert$).pipe(filter((event) => event.kind === kinds.GiftWrap), filter(isGiftWrapUnlocked), map((gift) => getGiftWrapSeal(gift)), distinct((seal) => seal.id));
|
|
113
|
+
const persistSeals = unlockedSeals$
|
|
114
|
+
.pipe(filter((seal) => isEncryptedContentFromCache(seal) === false), combineLatestWith(storage$))
|
|
117
115
|
.subscribe(async ([seal, storage]) => {
|
|
118
116
|
if (!seal)
|
|
119
117
|
return;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type ExternalIdentifiers = {
|
|
2
|
+
web: string;
|
|
3
|
+
"#": `#${string}`;
|
|
4
|
+
geo: `geo:${string}`;
|
|
5
|
+
isbn: `isbn:${string}`;
|
|
6
|
+
"podcast:guid": `podcast:guid:${string}`;
|
|
7
|
+
"podcast:item:guid": `podcast:item:guid:${string}`;
|
|
8
|
+
"podcast:publisher:guid": `podcast:publisher:guid:${string}`;
|
|
9
|
+
isan: `isan:${string}`;
|
|
10
|
+
doi: `doi:${string}`;
|
|
11
|
+
"bitcoin:tx": `bitcoin:tx:${string}`;
|
|
12
|
+
"bitcoin:address": `bitcoin:address:${string}`;
|
|
13
|
+
"ethereum:tx": `ethereum:${string}:tx:${string}`;
|
|
14
|
+
"ethereum:address": `ethereum:${string}:address:${string}`;
|
|
15
|
+
[key: `${string}:tx`]: `${string}:tx:${string}`;
|
|
16
|
+
[key: `${string}:address`]: `${string}:address:${string}`;
|
|
17
|
+
};
|
|
18
|
+
export type ExternalPointer<Prefix extends keyof ExternalIdentifiers> = {
|
|
19
|
+
kind: Prefix;
|
|
20
|
+
identifier: ExternalIdentifiers[Prefix];
|
|
21
|
+
};
|
|
22
|
+
export type ParseResult = {
|
|
23
|
+
[P in keyof ExternalIdentifiers]: ExternalPointer<P>;
|
|
24
|
+
}[keyof ExternalIdentifiers];
|
|
25
|
+
/** Casts a string to a valid external pointer */
|
|
26
|
+
export declare function isValidExternalPointer(identifier: string): identifier is `${keyof ExternalIdentifiers}1${string}`;
|
|
27
|
+
/** Parses a NIP-73 external identifier */
|
|
28
|
+
export declare function parseExternalPointer<Prefix extends keyof ExternalIdentifiers>(identifier: `${Prefix}1${string}`): ExternalPointer<Prefix>;
|
|
29
|
+
export declare function parseExternalPointer(identifier: string): ParseResult | null;
|
|
30
|
+
/** Gets an ExternalPointer for a "i" tag */
|
|
31
|
+
export declare function getExternalPointerFromTag<Prefix extends keyof ExternalIdentifiers>(tag: string[]): ExternalPointer<Prefix> | null;
|
|
32
|
+
export declare function getExternalPointerFromTag(tag: string[]): ParseResult | null;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Casts a string to a valid external pointer */
|
|
2
|
+
export function isValidExternalPointer(identifier) {
|
|
3
|
+
return parseExternalPointer(identifier) !== null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a URL according to NIP-73:
|
|
7
|
+
* - Removes fragment
|
|
8
|
+
* - Returns the normalized URL string
|
|
9
|
+
*/
|
|
10
|
+
function normalizeUrl(url) {
|
|
11
|
+
try {
|
|
12
|
+
const urlObj = new URL(url);
|
|
13
|
+
urlObj.hash = ""; // Remove fragment
|
|
14
|
+
return urlObj.toString();
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// If URL parsing fails, return original (will be caught by validation)
|
|
18
|
+
return url;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function parseExternalPointer(identifier) {
|
|
22
|
+
// Check explicit prefixes first (these take precedence over URL parsing)
|
|
23
|
+
if (identifier.startsWith("#"))
|
|
24
|
+
return { kind: "#", identifier: identifier };
|
|
25
|
+
if (identifier.startsWith("geo:"))
|
|
26
|
+
return { kind: "geo", identifier: identifier };
|
|
27
|
+
if (identifier.startsWith("isbn:"))
|
|
28
|
+
return { kind: "isbn", identifier: identifier };
|
|
29
|
+
if (identifier.startsWith("podcast:guid:"))
|
|
30
|
+
return { kind: "podcast:guid", identifier: identifier };
|
|
31
|
+
if (identifier.startsWith("podcast:item:guid:"))
|
|
32
|
+
return { kind: "podcast:item:guid", identifier: identifier };
|
|
33
|
+
if (identifier.startsWith("podcast:publisher:guid:"))
|
|
34
|
+
return { kind: "podcast:publisher:guid", identifier: identifier };
|
|
35
|
+
if (identifier.startsWith("isan:"))
|
|
36
|
+
return { kind: "isan", identifier: identifier };
|
|
37
|
+
if (identifier.startsWith("doi:"))
|
|
38
|
+
return { kind: "doi", identifier: identifier };
|
|
39
|
+
// Check for blockchain identifiers
|
|
40
|
+
// Bitcoin: bitcoin:tx:<txid> or bitcoin:address:<address>
|
|
41
|
+
if (identifier.startsWith("bitcoin:tx:")) {
|
|
42
|
+
return { kind: "bitcoin:tx", identifier: identifier };
|
|
43
|
+
}
|
|
44
|
+
if (identifier.startsWith("bitcoin:address:")) {
|
|
45
|
+
return { kind: "bitcoin:address", identifier: identifier };
|
|
46
|
+
}
|
|
47
|
+
// Ethereum: ethereum:<chainId>:tx:<txHash> or ethereum:<chainId>:address:<address>
|
|
48
|
+
const ethereumTxMatch = identifier.match(/^ethereum:(\d+):tx:(.+)$/);
|
|
49
|
+
if (ethereumTxMatch) {
|
|
50
|
+
return { kind: "ethereum:tx", identifier: identifier };
|
|
51
|
+
}
|
|
52
|
+
const ethereumAddressMatch = identifier.match(/^ethereum:(\d+):address:(.+)$/);
|
|
53
|
+
if (ethereumAddressMatch) {
|
|
54
|
+
return { kind: "ethereum:address", identifier: identifier };
|
|
55
|
+
}
|
|
56
|
+
// Other blockchains: <blockchain>:tx:<txid> or <blockchain>:address:<address>
|
|
57
|
+
// Exclude known prefixes to avoid false matches
|
|
58
|
+
const blockchainTxMatch = identifier.match(/^([a-z0-9]+):tx:(.+)$/);
|
|
59
|
+
if (blockchainTxMatch && !identifier.startsWith("bitcoin:") && !identifier.startsWith("ethereum:")) {
|
|
60
|
+
const blockchain = blockchainTxMatch[1];
|
|
61
|
+
return { kind: `${blockchain}:tx`, identifier: identifier };
|
|
62
|
+
}
|
|
63
|
+
const blockchainAddressMatch = identifier.match(/^([a-z0-9]+):address:(.+)$/);
|
|
64
|
+
if (blockchainAddressMatch && !identifier.startsWith("bitcoin:") && !identifier.startsWith("ethereum:")) {
|
|
65
|
+
const blockchain = blockchainAddressMatch[1];
|
|
66
|
+
return { kind: `${blockchain}:address`, identifier: identifier };
|
|
67
|
+
}
|
|
68
|
+
// Check for URL (must be a valid URL, normalized, no fragment)
|
|
69
|
+
// URLs don't have a prefix, so we check if it's a valid URL after checking all prefixes
|
|
70
|
+
try {
|
|
71
|
+
new URL(identifier); // Validate URL
|
|
72
|
+
// Valid URL - normalize it (remove fragment) and return
|
|
73
|
+
const normalized = normalizeUrl(identifier);
|
|
74
|
+
return { kind: "web", identifier: normalized };
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Not a valid URL
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
export function getExternalPointerFromTag(tag) {
|
|
82
|
+
if (!tag[1])
|
|
83
|
+
return null;
|
|
84
|
+
return parseExternalPointer(tag[1]);
|
|
85
|
+
}
|
|
@@ -35,10 +35,7 @@ export type FileMetadata = {
|
|
|
35
35
|
};
|
|
36
36
|
/** Alias for {@link FileMetadata} */
|
|
37
37
|
export type MediaAttachment = FileMetadata;
|
|
38
|
-
/**
|
|
39
|
-
* Parses file metadata tags into {@link FileMetadata}
|
|
40
|
-
* @throws
|
|
41
|
-
*/
|
|
38
|
+
/** Parses file metadata tags into {@link FileMetadata} */
|
|
42
39
|
export declare function parseFileMetadataTags(tags: string[][]): FileMetadata;
|
|
43
40
|
/** Parses a imeta tag into a {@link FileMetadata} */
|
|
44
41
|
export declare function getFileMetadataFromImetaTag(tag: string[]): FileMetadata;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
|
|
2
|
-
/**
|
|
3
|
-
* Parses file metadata tags into {@link FileMetadata}
|
|
4
|
-
* @throws
|
|
5
|
-
*/
|
|
2
|
+
/** Parses file metadata tags into {@link FileMetadata} */
|
|
6
3
|
export function parseFileMetadataTags(tags) {
|
|
7
4
|
const fields = {};
|
|
8
5
|
let fallback = undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EventMemory } from "applesauce-core/event-store";
|
|
2
|
+
import { safeParse } from "applesauce-core/helpers";
|
|
2
3
|
import { getEncryptedContent, isEncryptedContentUnlocked, lockEncryptedContent, unlockEncryptedContent, } from "applesauce-core/helpers/encrypted-content";
|
|
3
4
|
import { kinds, notifyEventUpdate, verifyWrappedEvent, } from "applesauce-core/helpers/event";
|
|
4
5
|
/**
|
|
@@ -64,7 +65,7 @@ export function getRumorGiftWraps(rumor) {
|
|
|
64
65
|
}
|
|
65
66
|
/** Checks if a seal event is locked and casts it to the {@link UnlockedSeal} type */
|
|
66
67
|
export function isSealUnlocked(seal) {
|
|
67
|
-
return isEncryptedContentUnlocked(seal) === true &&
|
|
68
|
+
return RumorSymbol in seal || (isEncryptedContentUnlocked(seal) === true && getSealRumor(seal) !== undefined);
|
|
68
69
|
}
|
|
69
70
|
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
70
71
|
export function isGiftWrapUnlocked(gift) {
|
|
@@ -84,7 +85,7 @@ export function getSealRumor(seal) {
|
|
|
84
85
|
if (seal.kind !== kinds.Seal)
|
|
85
86
|
return undefined;
|
|
86
87
|
// If unlocked return the rumor
|
|
87
|
-
if (
|
|
88
|
+
if (RumorSymbol in seal)
|
|
88
89
|
return seal[RumorSymbol];
|
|
89
90
|
// Get the encrypted content plaintext
|
|
90
91
|
const content = getEncryptedContent(seal);
|
|
@@ -92,7 +93,12 @@ export function getSealRumor(seal) {
|
|
|
92
93
|
if (!content)
|
|
93
94
|
return undefined;
|
|
94
95
|
// Parse the content as a rumor event
|
|
95
|
-
let rumor =
|
|
96
|
+
let rumor = safeParse(content);
|
|
97
|
+
// Failed to parse rumor, save undefined and return undefined
|
|
98
|
+
if (!rumor) {
|
|
99
|
+
Reflect.set(seal, RumorSymbol, undefined);
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
96
102
|
// Check if the rumor event already exists in the internal event set
|
|
97
103
|
const existing = internalGiftWrapEvents.getEvent(rumor.id);
|
|
98
104
|
if (existing)
|
|
@@ -112,8 +118,8 @@ export function getSealRumor(seal) {
|
|
|
112
118
|
}
|
|
113
119
|
export function getGiftWrapSeal(gift) {
|
|
114
120
|
// Returned cached seal if it exists (downstream)
|
|
115
|
-
if (
|
|
116
|
-
return
|
|
121
|
+
if (SealSymbol in gift)
|
|
122
|
+
return gift[SealSymbol];
|
|
117
123
|
// Get the encrypted content
|
|
118
124
|
const content = getEncryptedContent(gift);
|
|
119
125
|
// Return undefined if the content is not found
|