applesauce-core 3.1.0 → 4.0.0

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 (88) hide show
  1. package/dist/event-store/async-event-store.d.ts +134 -0
  2. package/dist/event-store/async-event-store.js +349 -0
  3. package/dist/event-store/{event-set.d.ts → event-memory.d.ts} +15 -25
  4. package/dist/event-store/{event-set.js → event-memory.js} +43 -53
  5. package/dist/event-store/event-store.d.ts +57 -63
  6. package/dist/event-store/event-store.js +111 -190
  7. package/dist/event-store/index.d.ts +2 -1
  8. package/dist/event-store/index.js +2 -1
  9. package/dist/event-store/interface.d.ts +111 -38
  10. package/dist/event-store/model-mixin.d.ts +59 -0
  11. package/dist/event-store/model-mixin.js +147 -0
  12. package/dist/helpers/app-data.d.ts +39 -0
  13. package/dist/helpers/app-data.js +68 -0
  14. package/dist/helpers/bookmarks.d.ts +11 -1
  15. package/dist/helpers/bookmarks.js +29 -4
  16. package/dist/helpers/comment.d.ts +13 -20
  17. package/dist/helpers/comment.js +16 -27
  18. package/dist/helpers/contacts.d.ts +10 -1
  19. package/dist/helpers/contacts.js +30 -3
  20. package/dist/helpers/encrypted-content-cache.js +7 -7
  21. package/dist/helpers/encrypted-content.d.ts +9 -2
  22. package/dist/helpers/encrypted-content.js +12 -9
  23. package/dist/helpers/event-cache.d.ts +3 -1
  24. package/dist/helpers/event-cache.js +3 -1
  25. package/dist/helpers/event-tags.d.ts +6 -0
  26. package/dist/helpers/event-tags.js +4 -0
  27. package/dist/helpers/event.d.ts +8 -1
  28. package/dist/helpers/event.js +6 -0
  29. package/dist/helpers/file-metadata.d.ts +4 -9
  30. package/dist/helpers/file-metadata.js +2 -10
  31. package/dist/helpers/filter.d.ts +4 -3
  32. package/dist/helpers/filter.js +3 -3
  33. package/dist/helpers/gift-wraps.d.ts +35 -14
  34. package/dist/helpers/gift-wraps.js +59 -50
  35. package/dist/helpers/groups.d.ts +2 -5
  36. package/dist/helpers/groups.js +2 -5
  37. package/dist/helpers/hidden-content.d.ts +14 -5
  38. package/dist/helpers/hidden-content.js +19 -8
  39. package/dist/helpers/hidden-tags.d.ts +16 -7
  40. package/dist/helpers/hidden-tags.js +47 -26
  41. package/dist/helpers/index.d.ts +1 -0
  42. package/dist/helpers/index.js +1 -0
  43. package/dist/helpers/legacy-messages.d.ts +17 -13
  44. package/dist/helpers/legacy-messages.js +21 -19
  45. package/dist/helpers/lists.js +2 -1
  46. package/dist/helpers/lnurl.d.ts +4 -0
  47. package/dist/helpers/lnurl.js +7 -3
  48. package/dist/helpers/mailboxes.d.ts +2 -6
  49. package/dist/helpers/mailboxes.js +26 -20
  50. package/dist/helpers/mutes.d.ts +11 -1
  51. package/dist/helpers/mutes.js +30 -5
  52. package/dist/helpers/picture-post.d.ts +2 -1
  53. package/dist/helpers/pointers.d.ts +1 -1
  54. package/dist/helpers/pointers.js +2 -1
  55. package/dist/helpers/profile.d.ts +7 -3
  56. package/dist/helpers/profile.js +7 -8
  57. package/dist/helpers/relay-selection.d.ts +13 -0
  58. package/dist/helpers/relay-selection.js +84 -0
  59. package/dist/helpers/relays.d.ts +3 -1
  60. package/dist/helpers/relays.js +18 -2
  61. package/dist/helpers/url.js +3 -3
  62. package/dist/helpers/wrapped-messages.d.ts +5 -3
  63. package/dist/helpers/wrapped-messages.js +5 -3
  64. package/dist/helpers/zap.d.ts +16 -14
  65. package/dist/helpers/zap.js +26 -28
  66. package/dist/models/common.d.ts +4 -4
  67. package/dist/models/common.js +79 -40
  68. package/dist/models/gift-wrap.d.ts +1 -1
  69. package/dist/models/gift-wrap.js +4 -4
  70. package/dist/models/index.d.ts +1 -0
  71. package/dist/models/index.js +1 -0
  72. package/dist/models/legacy-messages.d.ts +2 -2
  73. package/dist/models/legacy-messages.js +13 -10
  74. package/dist/models/outbox.d.ts +13 -0
  75. package/dist/models/outbox.js +18 -0
  76. package/dist/models/profile.d.ts +1 -1
  77. package/dist/models/zaps.d.ts +5 -4
  78. package/dist/models/zaps.js +2 -2
  79. package/dist/observable/index.d.ts +4 -3
  80. package/dist/observable/index.js +5 -4
  81. package/dist/observable/map-events-to-store.d.ts +5 -3
  82. package/dist/observable/map-events-to-store.js +14 -3
  83. package/dist/observable/map-events-to-timeline.js +12 -0
  84. package/dist/observable/relay-selection.d.ts +7 -0
  85. package/dist/observable/relay-selection.js +38 -0
  86. package/package.json +5 -3
  87. package/dist/observable/map-events-timeline.js +0 -9
  88. /package/dist/observable/{map-events-timeline.d.ts → map-events-to-timeline.d.ts} +0 -0
@@ -1,8 +1,13 @@
1
- import { EncryptedContentSigner, EncryptionMethod, getEncryptedContentEncryptionMethods } from "./encrypted-content.js";
1
+ import { EncryptedContentSigner, EncryptionMethod, getEncryptedContentEncryptionMethods, UnlockedEncryptedContent } from "./encrypted-content.js";
2
+ /** Symbol for caching hidden content. Alias for {@link EncryptedContentSymbol} */
2
3
  export declare const HiddenContentSymbol: symbol;
4
+ /** Alias for {@link EncryptedContentSigner} */
3
5
  export interface HiddenContentSigner extends EncryptedContentSigner {
4
6
  }
7
+ /** Alias for {@link getEncryptedContentEncryptionMethods} */
5
8
  export declare const getHiddenContentEncryptionMethods: typeof getEncryptedContentEncryptionMethods;
9
+ /** Type for events with unlocked hidden content. alias for {@link UnlockedEncryptedContent} */
10
+ export type UnlockedHiddenContent = UnlockedEncryptedContent;
6
11
  /** Various event kinds that can have hidden content */
7
12
  export declare const HiddenContentKinds: Set<number>;
8
13
  /** Sets the encryption method for hidden content on a kind */
@@ -14,12 +19,16 @@ export declare function hasHiddenContent<T extends {
14
19
  kind: number;
15
20
  content: string;
16
21
  }>(event: T): boolean;
17
- /** Checks if the hidden content is locked */
18
- export declare function isHiddenContentLocked<T extends object>(event: T): boolean;
22
+ /** Checks if the hidden content is unlocked and casts it to the {@link UnlockedEncryptedContent} type */
23
+ export declare function isHiddenContentUnlocked<T extends {
24
+ kind: number;
25
+ }>(event: T): event is T & UnlockedEncryptedContent;
19
26
  /** Returns the hidden content for an event if they are unlocked */
20
27
  export declare function getHiddenContent<T extends {
21
28
  kind: number;
22
- content: string;
29
+ } & UnlockedHiddenContent>(event: T): string;
30
+ export declare function getHiddenContent<T extends {
31
+ kind: number;
23
32
  }>(event: T): string | undefined;
24
33
  /**
25
34
  * Unlocks the hidden content in the event
@@ -34,7 +43,7 @@ export declare function unlockHiddenContent<T extends {
34
43
  }>(event: T, signer: EncryptedContentSigner, override?: EncryptionMethod): Promise<string>;
35
44
  /**
36
45
  * Sets the hidden content on an event and updates it if its part of an event store
37
- * @throws
46
+ * @throws If the event kind does not support hidden content
38
47
  */
39
48
  export declare function setHiddenContentCache<T extends {
40
49
  kind: number;
@@ -1,7 +1,8 @@
1
1
  import { kinds } from "nostr-tools";
2
- import { canHaveEncryptedContent, EncryptedContentSymbol, getEncryptedContent, getEncryptedContentEncryptionMethods, hasEncryptedContent, isEncryptedContentLocked, lockEncryptedContent, setEncryptedContentCache, setEncryptedContentEncryptionMethod, } from "./encrypted-content.js";
3
- // reexport from encrypted-content
2
+ import { canHaveEncryptedContent, EncryptedContentSymbol, getEncryptedContent, getEncryptedContentEncryptionMethods, hasEncryptedContent, isEncryptedContentUnlocked, lockEncryptedContent, setEncryptedContentCache, setEncryptedContentEncryptionMethod, } from "./encrypted-content.js";
3
+ /** Symbol for caching hidden content. Alias for {@link EncryptedContentSymbol} */
4
4
  export const HiddenContentSymbol = EncryptedContentSymbol;
5
+ /** Alias for {@link getEncryptedContentEncryptionMethods} */
5
6
  export const getHiddenContentEncryptionMethods = getEncryptedContentEncryptionMethods;
6
7
  /** Various event kinds that can have hidden content */
7
8
  export const HiddenContentKinds = new Set([setEncryptedContentEncryptionMethod(kinds.DraftLong, "nip04")]);
@@ -18,14 +19,17 @@ export function canHaveHiddenContent(kind) {
18
19
  export function hasHiddenContent(event) {
19
20
  return canHaveHiddenContent(event.kind) && hasEncryptedContent(event);
20
21
  }
21
- /** Checks if the hidden content is locked */
22
- export function isHiddenContentLocked(event) {
23
- return isEncryptedContentLocked(event);
22
+ /** Checks if the hidden content is unlocked and casts it to the {@link UnlockedEncryptedContent} type */
23
+ export function isHiddenContentUnlocked(event) {
24
+ if (!canHaveHiddenContent(event.kind))
25
+ return false;
26
+ return isEncryptedContentUnlocked(event) && Reflect.has(event, HiddenContentSymbol) === true;
24
27
  }
25
- /** Returns the hidden content for an event if they are unlocked */
26
28
  export function getHiddenContent(event) {
27
- if (!canHaveHiddenContent(event.kind) || isHiddenContentLocked(event))
29
+ if (!canHaveHiddenContent(event.kind))
28
30
  return undefined;
31
+ if (isHiddenContentUnlocked(event))
32
+ return event[EncryptedContentSymbol];
29
33
  return getEncryptedContent(event);
30
34
  }
31
35
  /**
@@ -37,14 +41,21 @@ export function getHiddenContent(event) {
37
41
  export async function unlockHiddenContent(event, signer, override) {
38
42
  if (!canHaveHiddenContent(event.kind))
39
43
  throw new Error("Event kind does not support hidden content");
44
+ // If the encrypted content is already unlocked, return the cached value
45
+ if (isEncryptedContentUnlocked(event))
46
+ return event[EncryptedContentSymbol];
47
+ // Get the encryption method from the signer
40
48
  const encryption = getEncryptedContentEncryptionMethods(event.kind, signer, override);
49
+ // Decrypt the content using the events pubkey
41
50
  const plaintext = await encryption.decrypt(event.pubkey, event.content);
51
+ // Set the cached value
42
52
  setHiddenContentCache(event, plaintext);
53
+ // Return the decrypted content
43
54
  return plaintext;
44
55
  }
45
56
  /**
46
57
  * Sets the hidden content on an event and updates it if its part of an event store
47
- * @throws
58
+ * @throws If the event kind does not support hidden content
48
59
  */
49
60
  export function setHiddenContentCache(event, plaintext) {
50
61
  if (!canHaveHiddenContent(event.kind))
@@ -1,6 +1,11 @@
1
- import { HiddenContentSigner } from "./hidden-content.js";
2
1
  import { EncryptionMethod } from "./encrypted-content.js";
2
+ import { HiddenContentSigner, UnlockedHiddenContent } from "./hidden-content.js";
3
+ /** Symbol for caching hidden tags. */
3
4
  export declare const HiddenTagsSymbol: unique symbol;
5
+ /** Type for events with unlocked hidden tags */
6
+ export type UnlockedHiddenTags = UnlockedHiddenContent & {
7
+ [HiddenTagsSymbol]: string[][];
8
+ };
4
9
  /** Various event kinds that can have hidden tags */
5
10
  export declare const HiddenTagsKinds: Set<number>;
6
11
  /** Checks if an event can have hidden tags */
@@ -12,15 +17,19 @@ export declare function hasHiddenTags<T extends {
12
17
  kind: number;
13
18
  content: string;
14
19
  }>(event: T): boolean;
20
+ /** Returns either nip04 or nip44 encryption method depending on list kind */
21
+ export declare function getHiddenTagsEncryptionMethods(kind: number, signer: HiddenContentSigner): import("./encrypted-content.js").EncryptionMethods;
22
+ /** Checks if the hidden tags are locked and casts it to the {@link UnlockedHiddenTags} type */
23
+ export declare function isHiddenTagsUnlocked<T extends {
24
+ kind: number;
25
+ }>(event: T): event is T & UnlockedHiddenTags;
15
26
  /** Returns the hidden tags for an event if they are unlocked */
16
27
  export declare function getHiddenTags<T extends {
17
28
  kind: number;
18
- content: string;
29
+ } & UnlockedHiddenTags>(event: T): string[][];
30
+ export declare function getHiddenTags<T extends {
31
+ kind: number;
19
32
  }>(event: T): string[][] | undefined;
20
- /** Checks if the hidden tags are locked */
21
- export declare function isHiddenTagsLocked<T extends object>(event: T): boolean;
22
- /** Returns either nip04 or nip44 encryption method depending on list kind */
23
- export declare function getHiddenTagsEncryptionMethods(kind: number, signer: HiddenContentSigner): import("./encrypted-content.js").EncryptionMethods;
24
33
  /**
25
34
  * Decrypts the private list
26
35
  * @param event The list event to decrypt
@@ -35,7 +44,7 @@ export declare function unlockHiddenTags<T extends {
35
44
  }>(event: T, signer: HiddenContentSigner, override?: EncryptionMethod): Promise<string[][]>;
36
45
  /**
37
46
  * Sets the hidden tags on an event and updates it if its part of an event store
38
- * @throws
47
+ * @throws If the event kind does not support hidden tags
39
48
  */
40
49
  export declare function setHiddenTagsCache<T extends {
41
50
  kind: number;
@@ -1,7 +1,7 @@
1
1
  import { kinds } from "nostr-tools";
2
- import { getOrComputeCachedValue } from "./cache.js";
3
- import { canHaveHiddenContent, getHiddenContent, getHiddenContentEncryptionMethods, hasHiddenContent, isHiddenContentLocked, lockHiddenContent, setHiddenContentCache, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "./hidden-content.js";
4
2
  import { GROUPS_LIST_KIND } from "./groups.js";
3
+ import { canHaveHiddenContent, getHiddenContent, getHiddenContentEncryptionMethods, hasHiddenContent, isHiddenContentUnlocked, lockHiddenContent, setHiddenContentCache, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "./hidden-content.js";
4
+ /** Symbol for caching hidden tags. */
5
5
  export const HiddenTagsSymbol = Symbol.for("hidden-tags");
6
6
  /** Various event kinds that can have hidden tags */
7
7
  export const HiddenTagsKinds = new Set([
@@ -33,27 +33,38 @@ export function setHiddenTagsEncryptionMethod(kind, method) {
33
33
  export function hasHiddenTags(event) {
34
34
  return canHaveHiddenTags(event.kind) && hasHiddenContent(event);
35
35
  }
36
- /** Returns the hidden tags for an event if they are unlocked */
37
- export function getHiddenTags(event) {
38
- if (!canHaveHiddenTags(event.kind) || isHiddenTagsLocked(event))
39
- return undefined;
40
- return getOrComputeCachedValue(event, HiddenTagsSymbol, () => {
41
- const plaintext = getHiddenContent(event);
42
- const parsed = JSON.parse(plaintext);
43
- if (!Array.isArray(parsed))
44
- throw new Error("Content is not an array of tags");
45
- // Convert array to tags array string[][]
46
- return parsed.filter((t) => Array.isArray(t)).map((t) => t.map((v) => String(v)));
47
- });
48
- }
49
- /** Checks if the hidden tags are locked */
50
- export function isHiddenTagsLocked(event) {
51
- return isHiddenContentLocked(event);
52
- }
53
36
  /** Returns either nip04 or nip44 encryption method depending on list kind */
54
37
  export function getHiddenTagsEncryptionMethods(kind, signer) {
55
38
  return getHiddenContentEncryptionMethods(kind, signer);
56
39
  }
40
+ /** Checks if the hidden tags are locked and casts it to the {@link UnlockedHiddenTags} type */
41
+ export function isHiddenTagsUnlocked(event) {
42
+ if (!canHaveHiddenTags(event.kind))
43
+ return false;
44
+ return isHiddenContentUnlocked(event) && Reflect.has(event, `HiddenTagsSymbol`);
45
+ }
46
+ export function getHiddenTags(event) {
47
+ if (!canHaveHiddenTags(event.kind))
48
+ return undefined;
49
+ // If the hidden tags are already unlocked, return the cached value
50
+ if (isHiddenTagsUnlocked(event))
51
+ return event[HiddenTagsSymbol];
52
+ // unlock hidden content is needed
53
+ const content = getHiddenContent(event);
54
+ // Return undefined if the hidden content is not unlocked
55
+ if (content === undefined)
56
+ return undefined;
57
+ // Parse the hidden content as an array of tags
58
+ const parsed = JSON.parse(content);
59
+ // Throw error if content is not an array of tags
60
+ if (!Array.isArray(parsed))
61
+ throw new Error("Content is not an array of tags");
62
+ // Convert array to tags array string[][]
63
+ const tags = parsed.filter((t) => Array.isArray(t)).map((t) => t.map((v) => String(v)));
64
+ // Set the cached value
65
+ Reflect.set(event, HiddenTagsSymbol, tags);
66
+ return tags;
67
+ }
57
68
  /**
58
69
  * Decrypts the private list
59
70
  * @param event The list event to decrypt
@@ -64,20 +75,30 @@ export function getHiddenTagsEncryptionMethods(kind, signer) {
64
75
  export async function unlockHiddenTags(event, signer, override) {
65
76
  if (!canHaveHiddenTags(event.kind))
66
77
  throw new Error("Event kind does not support hidden tags");
67
- // unlock hidden content is needed
68
- if (isHiddenContentLocked(event))
69
- await unlockHiddenContent(event, signer, override);
70
- return getHiddenTags(event);
78
+ // Return the cached value if the hidden tags are already unlocked
79
+ if (isHiddenTagsUnlocked(event))
80
+ return event[HiddenTagsSymbol];
81
+ // Unlock hidden content
82
+ await unlockHiddenContent(event, signer, override);
83
+ // Parse the hidden tags
84
+ const tags = getHiddenTags(event);
85
+ if (tags === undefined)
86
+ throw new Error("Failed to unlock hidden tags");
87
+ // Set cache an notify event store
88
+ setHiddenTagsCache(event, tags);
89
+ return tags;
71
90
  }
72
91
  /**
73
92
  * Sets the hidden tags on an event and updates it if its part of an event store
74
- * @throws
93
+ * @throws If the event kind does not support hidden tags
75
94
  */
76
95
  export function setHiddenTagsCache(event, tags) {
77
96
  if (!canHaveHiddenTags(event.kind))
78
97
  throw new Error("Event kind does not support hidden tags");
79
- const plaintext = JSON.stringify(tags);
80
- setHiddenContentCache(event, plaintext);
98
+ // Set the cached value
99
+ Reflect.set(event, HiddenTagsSymbol, tags);
100
+ // Set the cached content
101
+ setHiddenContentCache(event, JSON.stringify(tags));
81
102
  }
82
103
  /** Clears the cached hidden tags on an event */
83
104
  export function lockHiddenTags(event) {
@@ -43,6 +43,7 @@ export * from "./pointers.js";
43
43
  export * from "./poll.js";
44
44
  export * from "./profile.js";
45
45
  export * from "./reactions.js";
46
+ export * from "./relay-selection.js";
46
47
  export * from "./relays.js";
47
48
  export * from "./reports.js";
48
49
  export * from "./share.js";
@@ -43,6 +43,7 @@ export * from "./pointers.js";
43
43
  export * from "./poll.js";
44
44
  export * from "./profile.js";
45
45
  export * from "./reactions.js";
46
+ export * from "./relay-selection.js";
46
47
  export * from "./relays.js";
47
48
  export * from "./reports.js";
48
49
  export * from "./share.js";
@@ -1,21 +1,25 @@
1
- import { NostrEvent } from "nostr-tools";
2
- import { EncryptedContentSigner } from "./encrypted-content.js";
1
+ import { kinds, NostrEvent } from "nostr-tools";
2
+ import { EncryptedContentSigner, UnlockedEncryptedContent } from "./encrypted-content.js";
3
+ import { KnownEvent } from "./index.js";
4
+ /** Type for valid legacy direct messages */
5
+ export type LegacyMessage = KnownEvent<kinds.EncryptedDirectMessage>;
6
+ /** Type for a legacy direct message with unlocked encrypted content */
7
+ export type UnlockedLegacyMessage = LegacyMessage & UnlockedEncryptedContent;
3
8
  /** Checks if a legacy direct message content is encrypted */
4
- export declare function isLegacyMessageLocked(event: NostrEvent): boolean;
5
- /**
6
- * Returns the corraspondant of a legacy direct message
7
- * @throws if no corraspondant is found
8
- */
9
- export declare function getLegacyMessageCorraspondant(message: NostrEvent, self: string): string;
10
- /**
11
- * Returns the receiver of a legacy direct message
12
- * @throws if no receiver is found
13
- */
14
- export declare const getLegacyMessageReceiver: typeof getLegacyMessageCorraspondant;
9
+ export declare function isLegacyMessageUnlocked<T extends NostrEvent>(event: T): event is T & UnlockedEncryptedContent;
10
+ /** Returns the correspondent of a legacy direct message */
11
+ export declare function getLegacyMessageCorrespondent<T extends LegacyMessage>(message: T, self: string): string;
12
+ export declare function getLegacyMessageCorrespondent<T extends NostrEvent>(message: T, self: string): string | undefined;
13
+ /** Returns the receiver of a legacy direct me */
14
+ export declare const getLegacyMessageReceiver: typeof getLegacyMessageCorrespondent;
15
+ /** @deprecated use {@link getLegacyMessageCorrespondent} instead */
16
+ export declare const getLegacyMessageCorraspondant: typeof getLegacyMessageCorrespondent;
15
17
  /** Returns the sender of a legacy direct message */
16
18
  export declare function getLegacyMessageSender(message: NostrEvent): string;
17
19
  /** Returns the parent message id of a legacy message */
18
20
  export declare function getLegacyMessageParent(message: NostrEvent): string | undefined;
21
+ /** Checks if a legacy message is valid */
22
+ export declare function isValidLegacyMessage(event: any): event is LegacyMessage;
19
23
  /**
20
24
  * Returns the decrypted content of a direct message
21
25
  * @param message - The message to decrypt
@@ -1,24 +1,17 @@
1
- import { getEncryptedContent, isEncryptedContentLocked, lockEncryptedContent, unlockEncryptedContent, } from "./encrypted-content.js";
1
+ import { kinds } from "nostr-tools";
2
+ import { getEncryptedContent, isEncryptedContentUnlocked, lockEncryptedContent, unlockEncryptedContent, } from "./encrypted-content.js";
2
3
  import { getTagValue } from "./index.js";
3
4
  /** Checks if a legacy direct message content is encrypted */
4
- export function isLegacyMessageLocked(event) {
5
- return isEncryptedContentLocked(event);
5
+ export function isLegacyMessageUnlocked(event) {
6
+ return isEncryptedContentUnlocked(event);
6
7
  }
7
- /**
8
- * Returns the corraspondant of a legacy direct message
9
- * @throws if no corraspondant is found
10
- */
11
- export function getLegacyMessageCorraspondant(message, self) {
12
- const corraspondant = message.pubkey === self ? getTagValue(message, "p") : message.pubkey;
13
- if (!corraspondant)
14
- throw new Error("No corraspondant found");
15
- return corraspondant;
8
+ export function getLegacyMessageCorrespondent(message, self) {
9
+ return message.pubkey === self ? getTagValue(message, "p") : message.pubkey;
16
10
  }
17
- /**
18
- * Returns the receiver of a legacy direct message
19
- * @throws if no receiver is found
20
- */
21
- export const getLegacyMessageReceiver = getLegacyMessageCorraspondant;
11
+ /** Returns the receiver of a legacy direct me */
12
+ export const getLegacyMessageReceiver = getLegacyMessageCorrespondent;
13
+ /** @deprecated use {@link getLegacyMessageCorrespondent} instead */
14
+ export const getLegacyMessageCorraspondant = getLegacyMessageCorrespondent;
22
15
  /** Returns the sender of a legacy direct message */
23
16
  export function getLegacyMessageSender(message) {
24
17
  return message.pubkey;
@@ -27,6 +20,12 @@ export function getLegacyMessageSender(message) {
27
20
  export function getLegacyMessageParent(message) {
28
21
  return getTagValue(message, "e");
29
22
  }
23
+ /** Checks if a legacy message is valid */
24
+ export function isValidLegacyMessage(event) {
25
+ return (event.kind === kinds.EncryptedDirectMessage &&
26
+ getLegacyMessageCorrespondent(event, event.pubkey) !== undefined &&
27
+ event.content.length > 0);
28
+ }
30
29
  /**
31
30
  * Returns the decrypted content of a direct message
32
31
  * @param message - The message to decrypt
@@ -38,9 +37,12 @@ export async function unlockLegacyMessage(message, self, signer) {
38
37
  const cached = getEncryptedContent(message);
39
38
  if (cached)
40
39
  return cached;
41
- const corraspondant = getLegacyMessageCorraspondant(message, self);
40
+ // Get the correspondent
41
+ const correspondent = getLegacyMessageCorrespondent(message, self);
42
+ if (!correspondent)
43
+ throw new Error("No correspondent found");
42
44
  // Unlock the encrypted content
43
- return await unlockEncryptedContent(message, corraspondant, signer);
45
+ return await unlockEncryptedContent(message, correspondent, signer);
44
46
  }
45
47
  /** Clears the cached plaintext of a direct message */
46
48
  export async function lockLegacyMessage(message) {
@@ -97,7 +97,8 @@ export function isValidList(event) {
97
97
  if (isAddressableKind(event.kind)) {
98
98
  // event is a set
99
99
  // ensure the set has an identifier
100
- getReplaceableIdentifier(event);
100
+ if (!getReplaceableIdentifier(event))
101
+ return false;
101
102
  return true;
102
103
  }
103
104
  else if (isReplaceableKind(event.kind) && event.kind >= 10000 && event.kind < 20000) {
@@ -1,4 +1,8 @@
1
+ /** Parses a lightning address (lud16) into a LNURLp */
1
2
  export declare function parseLightningAddress(address: string): URL | undefined;
3
+ /** Parses a LNURLp into a URL */
2
4
  export declare function decodeLNURL(lnurl: string): URL | undefined;
5
+ /** Parses a lightning address or LNURLp into a URL */
3
6
  export declare function parseLNURLOrAddress(addressOrLNURL: string): URL | undefined;
7
+ /** Requests a bolt11 invoice from a LNURLp callback URL */
4
8
  export declare function getInvoice(callback: URL): Promise<string>;
@@ -1,12 +1,14 @@
1
1
  import { bech32 } from "@scure/base";
2
2
  import { parseBolt11 } from "./bolt11.js";
3
3
  const decoder = new TextDecoder();
4
+ /** Parses a lightning address (lud16) into a LNURLp */
4
5
  export function parseLightningAddress(address) {
5
6
  let [name, domain] = address.split("@");
6
7
  if (!name || !domain)
7
8
  return;
8
9
  return new URL(`https://${domain}/.well-known/lnurlp/${name}`);
9
10
  }
11
+ /** Parses a LNURLp into a URL */
10
12
  export function decodeLNURL(lnurl) {
11
13
  try {
12
14
  const { words, prefix } = bech32.decode(lnurl);
@@ -18,12 +20,14 @@ export function decodeLNURL(lnurl) {
18
20
  catch (error) { }
19
21
  return undefined;
20
22
  }
23
+ /** Parses a lightning address or LNURLp into a URL */
21
24
  export function parseLNURLOrAddress(addressOrLNURL) {
22
- if (addressOrLNURL.includes("@")) {
25
+ if (addressOrLNURL.includes("@"))
23
26
  return parseLightningAddress(addressOrLNURL);
24
- }
25
- return decodeLNURL(addressOrLNURL);
27
+ else
28
+ return decodeLNURL(addressOrLNURL);
26
29
  }
30
+ /** Requests a bolt11 invoice from a LNURLp callback URL */
27
31
  export async function getInvoice(callback) {
28
32
  const { pr: payRequest } = await fetch(callback).then((res) => res.json());
29
33
  const amount = callback.searchParams.get("amount");
@@ -1,11 +1,7 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
2
  export declare const MailboxesInboxesSymbol: unique symbol;
3
3
  export declare const MailboxesOutboxesSymbol: unique symbol;
4
- /**
5
- * Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol
6
- */
4
+ /** Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol */
7
5
  export declare function getInboxes(event: NostrEvent): string[];
8
- /**
9
- * Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol
10
- */
6
+ /** Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol */
11
7
  export declare function getOutboxes(event: NostrEvent): string[];
@@ -1,41 +1,47 @@
1
1
  import { getOrComputeCachedValue } from "./cache.js";
2
2
  import { isSafeRelayURL } from "./relays.js";
3
+ import { isRTag } from "./tags.js";
3
4
  import { normalizeURL } from "./url.js";
4
5
  export const MailboxesInboxesSymbol = Symbol.for("mailboxes-inboxes");
5
6
  export const MailboxesOutboxesSymbol = Symbol.for("mailboxes-outboxes");
6
- /**
7
- * Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol
8
- */
7
+ /** Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol */
9
8
  export function getInboxes(event) {
10
9
  return getOrComputeCachedValue(event, MailboxesInboxesSymbol, () => {
11
10
  const inboxes = [];
12
11
  for (const tag of event.tags) {
13
- const [name, url, mode] = tag;
14
- if (name === "r" &&
15
- url &&
16
- isSafeRelayURL(url) &&
17
- !inboxes.includes(url) &&
18
- (mode === "read" || mode === undefined)) {
19
- inboxes.push(normalizeURL(url));
12
+ if (!isRTag(tag))
13
+ continue;
14
+ try {
15
+ const [, url, mode] = tag;
16
+ if (url && isSafeRelayURL(url) && !inboxes.includes(url) && (mode === "read" || mode === undefined)) {
17
+ inboxes.push(normalizeURL(url));
18
+ }
19
+ }
20
+ catch {
21
+ // Ignore invalid url tags
20
22
  }
21
23
  }
22
24
  return inboxes;
23
25
  });
24
26
  }
25
- /**
26
- * Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol
27
- */
27
+ /** Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol */
28
28
  export function getOutboxes(event) {
29
29
  return getOrComputeCachedValue(event, MailboxesOutboxesSymbol, () => {
30
30
  const outboxes = [];
31
31
  for (const tag of event.tags) {
32
- const [name, url, mode] = tag;
33
- if (name === "r" &&
34
- url &&
35
- isSafeRelayURL(url) &&
36
- !outboxes.includes(url) &&
37
- (mode === "write" || mode === undefined)) {
38
- outboxes.push(normalizeURL(url));
32
+ if (!isRTag(tag))
33
+ continue;
34
+ try {
35
+ const [name, url, mode] = tag;
36
+ if (name === "r" &&
37
+ isSafeRelayURL(url) &&
38
+ !outboxes.includes(url) &&
39
+ (mode === "write" || mode === undefined)) {
40
+ outboxes.push(normalizeURL(url));
41
+ }
42
+ }
43
+ catch {
44
+ // Ignore invalid url tags
39
45
  }
40
46
  }
41
47
  return outboxes;
@@ -1,6 +1,11 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
+ import { HiddenContentSigner } from "./index.js";
2
3
  export declare const MutePublicSymbol: unique symbol;
3
4
  export declare const MuteHiddenSymbol: unique symbol;
5
+ /** Type for unlocked mute events */
6
+ export type UnlockedMutes = {
7
+ [MuteHiddenSymbol]: Mutes;
8
+ };
4
9
  export type Mutes = {
5
10
  pubkeys: Set<string>;
6
11
  threads: Set<string>;
@@ -15,8 +20,13 @@ export declare function parseMutedTags(tags: string[][]): Mutes;
15
20
  export declare function getMutedThings(mute: NostrEvent): Mutes;
16
21
  /** Returns only the public muted things from a mute event */
17
22
  export declare function getPublicMutedThings(mute: NostrEvent): Mutes;
23
+ /** Checks if the hidden mutes are unlocked */
24
+ export declare function isHiddenMutesUnlocked<T extends NostrEvent>(mute: T): mute is T & UnlockedMutes;
18
25
  /** Returns the hidden muted content if the event is unlocked */
19
- export declare function getHiddenMutedThings(mute: NostrEvent): Mutes | undefined;
26
+ export declare function getHiddenMutedThings<T extends NostrEvent & UnlockedMutes>(mute: T): Mutes;
27
+ export declare function getHiddenMutedThings<T extends NostrEvent>(mute: T): Mutes | undefined;
28
+ /** Unlocks the hidden mutes */
29
+ export declare function unlockHiddenMutes(mute: NostrEvent, signer: HiddenContentSigner): Promise<Mutes>;
20
30
  /** Creates a RegExp for matching muted words */
21
31
  export declare function createMutedWordsRegExp(mutedWords: string[]): RegExp;
22
32
  /** Returns true if the event matches the mutes */
@@ -1,7 +1,7 @@
1
1
  import { kinds } from "nostr-tools";
2
2
  import { getOrComputeCachedValue } from "./cache.js";
3
- import { getHiddenTags, isHiddenTagsLocked } from "./hidden-tags.js";
4
- import { getIndexableTags, getNip10References } from "./index.js";
3
+ import { getHiddenTags, isHiddenTagsUnlocked, unlockHiddenTags } from "./hidden-tags.js";
4
+ import { getIndexableTags, getNip10References, notifyEventUpdate } from "./index.js";
5
5
  import { isETag, isPTag, isTTag } from "./tags.js";
6
6
  export const MutePublicSymbol = Symbol.for("mute-public");
7
7
  export const MuteHiddenSymbol = Symbol.for("mute-hidden");
@@ -40,11 +40,36 @@ export function getMutedThings(mute) {
40
40
  export function getPublicMutedThings(mute) {
41
41
  return getOrComputeCachedValue(mute, MutePublicSymbol, () => parseMutedTags(mute.tags));
42
42
  }
43
- /** Returns the hidden muted content if the event is unlocked */
43
+ /** Checks if the hidden mutes are unlocked */
44
+ export function isHiddenMutesUnlocked(mute) {
45
+ return isHiddenTagsUnlocked(mute) && Reflect.has(mute, MuteHiddenSymbol);
46
+ }
44
47
  export function getHiddenMutedThings(mute) {
45
- if (isHiddenTagsLocked(mute))
48
+ if (isHiddenMutesUnlocked(mute))
49
+ return mute[MuteHiddenSymbol];
50
+ // get hidden tags
51
+ const tags = getHiddenTags(mute);
52
+ if (!tags)
46
53
  return undefined;
47
- return getOrComputeCachedValue(mute, MuteHiddenSymbol, () => parseMutedTags(getHiddenTags(mute)));
54
+ // parse muted tags
55
+ const mutes = parseMutedTags(tags);
56
+ // set cached value
57
+ Reflect.set(mute, MuteHiddenSymbol, mutes);
58
+ return mutes;
59
+ }
60
+ /** Unlocks the hidden mutes */
61
+ export async function unlockHiddenMutes(mute, signer) {
62
+ if (isHiddenMutesUnlocked(mute))
63
+ return mute[MuteHiddenSymbol];
64
+ // Unlock hidden tags
65
+ await unlockHiddenTags(mute, signer);
66
+ // get hidden mutes
67
+ const mutes = getHiddenMutedThings(mute);
68
+ if (!mutes)
69
+ throw new Error("Failed to unlock hidden mutes");
70
+ // Notify event store
71
+ notifyEventUpdate(mute);
72
+ return mutes;
48
73
  }
49
74
  /** Creates a RegExp for matching muted words */
50
75
  export function createMutedWordsRegExp(mutedWords) {
@@ -1,4 +1,5 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
+ import { FileMetadata } from "./file-metadata.js";
2
3
  export declare const PICTURE_POST_KIND = 20;
3
4
  /** Return the media attachments from a kind 20 media post */
4
- export declare function getPicturePostAttachments(post: NostrEvent): import("./file-metadata.js").FileMetadata[];
5
+ export declare function getPicturePostAttachments(post: NostrEvent): FileMetadata[];
@@ -15,7 +15,7 @@ export declare function parseCoordinate(a: string, requireD: false, silent: true
15
15
  /** Extra a pubkey from the result of nip19.decode */
16
16
  export declare function getPubkeyFromDecodeResult(result?: DecodeResult): string | undefined;
17
17
  /** Encodes the result of nip19.decode */
18
- export declare function encodeDecodeResult(result: DecodeResult): "" | `nprofile1${string}` | `nevent1${string}` | `naddr1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
18
+ export declare function encodeDecodeResult(result: DecodeResult): "" | `nevent1${string}` | `naddr1${string}` | `nprofile1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
19
19
  /**
20
20
  * Gets an EventPointer form a common "e" tag
21
21
  * @throws
@@ -5,6 +5,7 @@ import { isAddressableKind } from "nostr-tools/kinds";
5
5
  import { isSafeRelayURL, mergeRelaySets } from "./relays.js";
6
6
  import { isHexKey } from "./string.js";
7
7
  import { hexToBytes } from "@noble/hashes/utils";
8
+ import { normalizeURL } from "./url.js";
8
9
  export function parseCoordinate(a, requireD = false, silent = true) {
9
10
  const parts = a.split(":");
10
11
  const kind = parts[0] ? parseInt(parts[0]) : undefined;
@@ -117,7 +118,7 @@ export function getProfilePointerFromPTag(tag) {
117
118
  throw new Error("Invalid pubkey");
118
119
  const pointer = { pubkey: tag[1] };
119
120
  if (tag[2] && isSafeRelayURL(tag[2]))
120
- pointer.relays = [tag[2]];
121
+ pointer.relays = [normalizeURL(tag[2])];
121
122
  return pointer;
122
123
  }
123
124
  /** Checks if a pointer is an AddressPointer */