applesauce-core 3.1.0 → 4.1.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.
- package/dist/event-store/async-event-store.d.ts +136 -0
- package/dist/event-store/async-event-store.js +364 -0
- package/dist/event-store/{event-set.d.ts → event-memory.d.ts} +17 -25
- package/dist/event-store/{event-set.js → event-memory.js} +54 -53
- package/dist/event-store/event-store.d.ts +59 -63
- package/dist/event-store/event-store.js +126 -190
- package/dist/event-store/index.d.ts +2 -1
- package/dist/event-store/index.js +2 -1
- package/dist/event-store/interface.d.ts +115 -38
- package/dist/event-store/model-mixin.d.ts +59 -0
- package/dist/event-store/model-mixin.js +147 -0
- package/dist/helpers/app-data.d.ts +39 -0
- package/dist/helpers/app-data.js +68 -0
- package/dist/helpers/bookmarks.d.ts +11 -1
- package/dist/helpers/bookmarks.js +29 -4
- package/dist/helpers/comment.d.ts +13 -20
- package/dist/helpers/comment.js +16 -27
- package/dist/helpers/contacts.d.ts +10 -1
- package/dist/helpers/contacts.js +30 -3
- package/dist/helpers/encrypted-content-cache.js +7 -7
- package/dist/helpers/encrypted-content.d.ts +9 -2
- package/dist/helpers/encrypted-content.js +12 -9
- package/dist/helpers/event-cache.d.ts +3 -1
- package/dist/helpers/event-cache.js +3 -1
- package/dist/helpers/event-tags.d.ts +6 -0
- package/dist/helpers/event-tags.js +4 -0
- package/dist/helpers/event.d.ts +8 -1
- package/dist/helpers/event.js +6 -0
- package/dist/helpers/file-metadata.d.ts +4 -9
- package/dist/helpers/file-metadata.js +2 -10
- package/dist/helpers/filter.d.ts +4 -3
- package/dist/helpers/filter.js +3 -3
- package/dist/helpers/gift-wraps.d.ts +35 -14
- package/dist/helpers/gift-wraps.js +59 -50
- package/dist/helpers/groups.d.ts +2 -5
- package/dist/helpers/groups.js +2 -5
- package/dist/helpers/hidden-content.d.ts +14 -5
- package/dist/helpers/hidden-content.js +19 -8
- package/dist/helpers/hidden-tags.d.ts +16 -7
- package/dist/helpers/hidden-tags.js +47 -26
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/legacy-messages.d.ts +17 -13
- package/dist/helpers/legacy-messages.js +21 -19
- package/dist/helpers/lists.js +2 -1
- package/dist/helpers/lnurl.d.ts +4 -0
- package/dist/helpers/lnurl.js +7 -3
- package/dist/helpers/mailboxes.d.ts +2 -6
- package/dist/helpers/mailboxes.js +26 -20
- package/dist/helpers/mutes.d.ts +11 -1
- package/dist/helpers/mutes.js +30 -5
- package/dist/helpers/picture-post.d.ts +2 -1
- package/dist/helpers/pointers.d.ts +3 -1
- package/dist/helpers/pointers.js +4 -1
- package/dist/helpers/profile.d.ts +7 -3
- package/dist/helpers/profile.js +7 -8
- package/dist/helpers/relay-selection.d.ts +17 -0
- package/dist/helpers/relay-selection.js +102 -0
- package/dist/helpers/relays.d.ts +3 -1
- package/dist/helpers/relays.js +18 -2
- package/dist/helpers/url.js +3 -3
- package/dist/helpers/wrapped-messages.d.ts +5 -3
- package/dist/helpers/wrapped-messages.js +5 -3
- package/dist/helpers/zap.d.ts +18 -14
- package/dist/helpers/zap.js +26 -28
- package/dist/models/common.d.ts +4 -4
- package/dist/models/common.js +79 -40
- package/dist/models/gift-wrap.d.ts +1 -1
- package/dist/models/gift-wrap.js +4 -4
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/legacy-messages.d.ts +2 -2
- package/dist/models/legacy-messages.js +13 -10
- package/dist/models/outbox.d.ts +13 -0
- package/dist/models/outbox.js +18 -0
- package/dist/models/profile.d.ts +1 -1
- package/dist/models/zaps.d.ts +5 -4
- package/dist/models/zaps.js +2 -2
- package/dist/observable/index.d.ts +4 -3
- package/dist/observable/index.js +5 -4
- package/dist/observable/map-events-to-store.d.ts +5 -3
- package/dist/observable/map-events-to-store.js +14 -3
- package/dist/observable/map-events-to-timeline.js +12 -0
- package/dist/observable/relay-selection.d.ts +9 -0
- package/dist/observable/relay-selection.js +43 -0
- package/package.json +5 -3
- package/dist/observable/map-events-timeline.js +0 -9
- /package/dist/observable/{map-events-timeline.d.ts → map-events-to-timeline.d.ts} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { verifyEvent } from "nostr-tools";
|
|
2
|
-
import {
|
|
3
|
-
import { getEncryptedContent,
|
|
1
|
+
import { kinds, verifyEvent } from "nostr-tools";
|
|
2
|
+
import { EventMemory } from "../event-store/event-memory.js";
|
|
3
|
+
import { getEncryptedContent, isEncryptedContentUnlocked, lockEncryptedContent, unlockEncryptedContent, } from "./encrypted-content.js";
|
|
4
4
|
import { notifyEventUpdate } from "./event.js";
|
|
5
5
|
/**
|
|
6
6
|
* An internal event set to keep track of seals and rumors
|
|
7
|
-
* This is
|
|
7
|
+
* This is intentionally isolated from the main applications event store so to prevent seals and rumors from being leaked
|
|
8
8
|
*/
|
|
9
|
-
export const internalGiftWrapEvents = new
|
|
9
|
+
export const internalGiftWrapEvents = new EventMemory();
|
|
10
10
|
/** Used to store a reference to the seal event on gift wraps (downstream) or the seal event on rumors (upstream[]) */
|
|
11
11
|
export const SealSymbol = Symbol.for("seal");
|
|
12
12
|
/** Used to store a reference to the rumor on seals (downstream) */
|
|
@@ -40,7 +40,6 @@ export function isRumor(event) {
|
|
|
40
40
|
typeof event.created_at === "number" &&
|
|
41
41
|
event.created_at > 0);
|
|
42
42
|
}
|
|
43
|
-
/** Returns all the parent gift wraps for a seal event */
|
|
44
43
|
export function getSealGiftWrap(seal) {
|
|
45
44
|
return Reflect.get(seal, GiftWrapSymbol);
|
|
46
45
|
}
|
|
@@ -64,21 +63,37 @@ export function getRumorGiftWraps(rumor) {
|
|
|
64
63
|
}
|
|
65
64
|
return Array.from(giftWraps);
|
|
66
65
|
}
|
|
67
|
-
/** Checks if a seal event is locked */
|
|
68
|
-
export function
|
|
69
|
-
return
|
|
66
|
+
/** Checks if a seal event is locked and casts it to the {@link UnlockedSeal} type */
|
|
67
|
+
export function isSealUnlocked(seal) {
|
|
68
|
+
return isEncryptedContentUnlocked(seal) === true && Reflect.has(seal, RumorSymbol) === true;
|
|
69
|
+
}
|
|
70
|
+
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
71
|
+
export function isGiftWrapUnlocked(gift) {
|
|
72
|
+
if (isEncryptedContentUnlocked(gift) === false)
|
|
73
|
+
return false;
|
|
74
|
+
// Get the seal event
|
|
75
|
+
const seal = getGiftWrapSeal(gift);
|
|
76
|
+
if (!seal)
|
|
77
|
+
return false;
|
|
78
|
+
// If seal is locked, return false
|
|
79
|
+
if (!isSealUnlocked(seal))
|
|
80
|
+
return false;
|
|
81
|
+
return true;
|
|
70
82
|
}
|
|
71
|
-
/** Gets the rumor from a seal event */
|
|
72
83
|
export function getSealRumor(seal) {
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
// Non seal events cant have rumors
|
|
85
|
+
if (seal.kind !== kinds.Seal)
|
|
86
|
+
return undefined;
|
|
87
|
+
// If unlocked return the rumor
|
|
88
|
+
if (isSealUnlocked(seal))
|
|
89
|
+
return seal[RumorSymbol];
|
|
77
90
|
// Get the encrypted content plaintext
|
|
78
|
-
const
|
|
79
|
-
if
|
|
91
|
+
const content = getEncryptedContent(seal);
|
|
92
|
+
// Return undefined if the content is not found
|
|
93
|
+
if (!content)
|
|
80
94
|
return undefined;
|
|
81
|
-
|
|
95
|
+
// Parse the content as a rumor event
|
|
96
|
+
let rumor = JSON.parse(content);
|
|
82
97
|
// Check if the rumor event already exists in the internal event set
|
|
83
98
|
const existing = internalGiftWrapEvents.getEvent(rumor.id);
|
|
84
99
|
if (existing)
|
|
@@ -87,23 +102,26 @@ export function getSealRumor(seal) {
|
|
|
87
102
|
else
|
|
88
103
|
// Add to the internal event set
|
|
89
104
|
internalGiftWrapEvents.add(rumor);
|
|
105
|
+
// Throw an error if the seal and rumor authors do not match
|
|
106
|
+
if (rumor.pubkey !== seal.pubkey)
|
|
107
|
+
throw new Error("Seal author does not match rumor author");
|
|
90
108
|
// Save a reference to the parent seal event
|
|
91
109
|
addParentSealReference(rumor, seal);
|
|
92
|
-
//
|
|
110
|
+
// Cache the rumor event
|
|
93
111
|
Reflect.set(seal, RumorSymbol, rumor);
|
|
94
112
|
return rumor;
|
|
95
113
|
}
|
|
96
|
-
/** Returns the seal event in a gift-wrap event */
|
|
97
114
|
export function getGiftWrapSeal(gift) {
|
|
98
115
|
// Returned cached seal if it exists (downstream)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (!
|
|
116
|
+
if (Reflect.has(gift, SealSymbol))
|
|
117
|
+
return Reflect.get(gift, SealSymbol);
|
|
118
|
+
// Get the encrypted content
|
|
119
|
+
const content = getEncryptedContent(gift);
|
|
120
|
+
// Return undefined if the content is not found
|
|
121
|
+
if (!content)
|
|
105
122
|
return undefined;
|
|
106
|
-
|
|
123
|
+
// Parse seal as nostr event
|
|
124
|
+
let seal = JSON.parse(content);
|
|
107
125
|
// Check if the seal event already exists in the internal event set
|
|
108
126
|
const existing = internalGiftWrapEvents.getEvent(seal.id);
|
|
109
127
|
if (existing) {
|
|
@@ -122,39 +140,27 @@ export function getGiftWrapSeal(gift) {
|
|
|
122
140
|
Reflect.set(gift, SealSymbol, seal);
|
|
123
141
|
return seal;
|
|
124
142
|
}
|
|
125
|
-
/** Returns the unsigned rumor in the gift-wrap */
|
|
126
143
|
export function getGiftWrapRumor(gift) {
|
|
127
144
|
const seal = getGiftWrapSeal(gift);
|
|
128
145
|
if (!seal)
|
|
129
146
|
return undefined;
|
|
130
147
|
return getSealRumor(seal);
|
|
131
148
|
}
|
|
132
|
-
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
133
|
-
export function isGiftWrapLocked(gift) {
|
|
134
|
-
if (isEncryptedContentLocked(gift))
|
|
135
|
-
return true;
|
|
136
|
-
else {
|
|
137
|
-
const seal = getGiftWrapSeal(gift);
|
|
138
|
-
if (!seal || isSealLocked(seal))
|
|
139
|
-
return true;
|
|
140
|
-
else
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
149
|
/**
|
|
145
150
|
* Unlocks a seal event and returns the rumor event
|
|
146
151
|
* @throws {Error} If the author of the rumor event does not match the author of the seal
|
|
147
152
|
*/
|
|
148
153
|
export async function unlockSeal(seal, signer) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
// If already unlocked, return the rumor
|
|
155
|
+
if (isSealUnlocked(seal))
|
|
156
|
+
return seal[RumorSymbol];
|
|
157
|
+
// unlock encrypted content as needed
|
|
158
|
+
await unlockEncryptedContent(seal, seal.pubkey, signer);
|
|
152
159
|
const rumor = getSealRumor(seal);
|
|
153
160
|
if (!rumor)
|
|
154
161
|
throw new Error("Failed to read rumor in gift wrap");
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
throw new Error("Seal author does not match rumor author");
|
|
162
|
+
// Notify event store
|
|
163
|
+
notifyEventUpdate(seal);
|
|
158
164
|
return rumor;
|
|
159
165
|
}
|
|
160
166
|
/**
|
|
@@ -162,11 +168,13 @@ export async function unlockSeal(seal, signer) {
|
|
|
162
168
|
* @throws {Error} If the author of the rumor event does not match the author of the seal
|
|
163
169
|
*/
|
|
164
170
|
export async function unlockGiftWrap(gift, signer) {
|
|
165
|
-
//
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
|
|
171
|
+
// If already unlocked, return the rumor
|
|
172
|
+
if (isGiftWrapUnlocked(gift))
|
|
173
|
+
return getGiftWrapRumor(gift);
|
|
174
|
+
// Unlock the encrypted content
|
|
175
|
+
await unlockEncryptedContent(gift, gift.pubkey, signer);
|
|
176
|
+
// Parse seal as nostr event
|
|
177
|
+
let seal = getGiftWrapSeal(gift);
|
|
170
178
|
if (!seal)
|
|
171
179
|
throw new Error("Failed to read seal in gift wrap");
|
|
172
180
|
// Unlock the seal event
|
|
@@ -175,6 +183,7 @@ export async function unlockGiftWrap(gift, signer) {
|
|
|
175
183
|
notifyEventUpdate(gift);
|
|
176
184
|
return rumor;
|
|
177
185
|
}
|
|
186
|
+
/** Locks a gift-wrap event and seals its seal event */
|
|
178
187
|
export function lockGiftWrap(gift) {
|
|
179
188
|
const seal = getGiftWrapSeal(gift);
|
|
180
189
|
if (seal) {
|
package/dist/helpers/groups.d.ts
CHANGED
|
@@ -10,11 +10,8 @@ export type GroupPointer = {
|
|
|
10
10
|
/** The name of the group */
|
|
11
11
|
name?: string;
|
|
12
12
|
};
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
* @throws
|
|
16
|
-
*/
|
|
17
|
-
export declare function decodeGroupPointer(str: string): GroupPointer;
|
|
13
|
+
/** decodes a group identifier into a group pointer object */
|
|
14
|
+
export declare function decodeGroupPointer(str: string): GroupPointer | null;
|
|
18
15
|
/** Converts a group pointer into a group identifier */
|
|
19
16
|
export declare function encodeGroupPointer(pointer: GroupPointer): string;
|
|
20
17
|
export declare const GroupsPublicSymbol: unique symbol;
|
package/dist/helpers/groups.js
CHANGED
|
@@ -4,14 +4,11 @@ import { processTags } from "./tags.js";
|
|
|
4
4
|
import { normalizeURL } from "./url.js";
|
|
5
5
|
export const GROUPS_LIST_KIND = 10009;
|
|
6
6
|
export const GROUP_MESSAGE_KIND = 9;
|
|
7
|
-
/**
|
|
8
|
-
* decodes a group identifier into a group pointer object
|
|
9
|
-
* @throws
|
|
10
|
-
*/
|
|
7
|
+
/** decodes a group identifier into a group pointer object */
|
|
11
8
|
export function decodeGroupPointer(str) {
|
|
12
9
|
let [relay, id] = str.split("'");
|
|
13
10
|
if (!relay)
|
|
14
|
-
|
|
11
|
+
return null;
|
|
15
12
|
// Prepend wss:// if missing
|
|
16
13
|
if (!relay.match(/^wss?:/))
|
|
17
14
|
relay = `wss://${relay}`;
|
|
@@ -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
|
|
18
|
-
export declare function
|
|
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
|
-
|
|
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,
|
|
3
|
-
|
|
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
|
|
22
|
-
export function
|
|
23
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
//
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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) {
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/helpers/index.js
CHANGED
|
@@ -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
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*/
|
|
9
|
-
export declare
|
|
10
|
-
/**
|
|
11
|
-
|
|
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 {
|
|
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
|
|
5
|
-
return
|
|
5
|
+
export function isLegacyMessageUnlocked(event) {
|
|
6
|
+
return isEncryptedContentUnlocked(event);
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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,
|
|
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) {
|
package/dist/helpers/lists.js
CHANGED
|
@@ -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) {
|
package/dist/helpers/lnurl.d.ts
CHANGED
|
@@ -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>;
|
package/dist/helpers/lnurl.js
CHANGED
|
@@ -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
|
-
|
|
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");
|