applesauce-core 0.10.0 → 0.12.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/__tests__/fixtures.d.ts +8 -0
- package/dist/__tests__/fixtures.js +20 -0
- package/dist/event-store/__tests__/event-store.test.js +272 -0
- package/dist/event-store/database.d.ts +7 -5
- package/dist/event-store/database.js +14 -8
- package/dist/event-store/event-store.d.ts +40 -20
- package/dist/event-store/event-store.js +269 -314
- package/dist/event-store/index.d.ts +1 -0
- package/dist/event-store/index.js +1 -0
- package/dist/event-store/interface.d.ts +27 -0
- package/dist/helpers/__tests__/blossom.test.js +13 -0
- package/dist/helpers/__tests__/comment.test.d.ts +1 -0
- package/dist/helpers/__tests__/comment.test.js +235 -0
- package/dist/helpers/__tests__/emoji.test.d.ts +1 -0
- package/dist/helpers/__tests__/emoji.test.js +15 -0
- package/dist/helpers/__tests__/event.test.d.ts +1 -0
- package/dist/helpers/__tests__/event.test.js +36 -0
- package/dist/helpers/__tests__/file-metadata.test.d.ts +1 -0
- package/dist/helpers/__tests__/file-metadata.test.js +103 -0
- package/dist/helpers/__tests__/hidden-tags.test.d.ts +1 -0
- package/dist/helpers/{hidden-tags.test.js → __tests__/hidden-tags.test.js} +2 -1
- package/dist/helpers/__tests__/mailboxes.test.d.ts +1 -0
- package/dist/helpers/{mailboxes.test.js → __tests__/mailboxes.test.js} +1 -1
- package/dist/helpers/__tests__/nip-19.test.d.ts +1 -0
- package/dist/helpers/__tests__/nip-19.test.js +42 -0
- package/dist/helpers/__tests__/relays.test.d.ts +1 -0
- package/dist/helpers/__tests__/relays.test.js +21 -0
- package/dist/helpers/__tests__/tags.test.d.ts +1 -0
- package/dist/helpers/__tests__/tags.test.js +24 -0
- package/dist/helpers/__tests__/threading.test.d.ts +1 -0
- package/dist/helpers/{threading.test.js → __tests__/threading.test.js} +1 -1
- package/dist/helpers/blossom.d.ts +9 -0
- package/dist/helpers/blossom.js +22 -0
- package/dist/helpers/bookmarks.d.ts +15 -0
- package/dist/helpers/bookmarks.js +27 -0
- package/dist/helpers/cache.d.ts +3 -4
- package/dist/helpers/cache.js +1 -1
- package/dist/helpers/channels.d.ts +10 -0
- package/dist/helpers/channels.js +27 -0
- package/dist/helpers/comment.d.ts +3 -4
- package/dist/helpers/comment.js +20 -16
- package/dist/helpers/contacts.d.ts +3 -0
- package/dist/helpers/contacts.js +25 -0
- package/dist/helpers/direct-messages.d.ts +4 -0
- package/dist/helpers/direct-messages.js +5 -0
- package/dist/helpers/dns-identity.d.ts +7 -0
- package/dist/helpers/dns-identity.js +10 -0
- package/dist/helpers/emoji.d.ts +3 -1
- package/dist/helpers/emoji.js +2 -2
- package/dist/helpers/event.d.ts +15 -1
- package/dist/helpers/event.js +34 -11
- package/dist/helpers/file-metadata.d.ts +55 -0
- package/dist/helpers/file-metadata.js +99 -0
- package/dist/helpers/filter.d.ts +4 -0
- package/dist/helpers/filter.js +34 -1
- package/dist/helpers/gift-wraps.d.ts +12 -0
- package/dist/helpers/gift-wraps.js +49 -0
- package/dist/helpers/groups.d.ts +24 -0
- package/dist/helpers/groups.js +39 -0
- package/dist/helpers/hidden-content.d.ts +48 -0
- package/dist/helpers/hidden-content.js +88 -0
- package/dist/helpers/hidden-tags.d.ts +17 -35
- package/dist/helpers/hidden-tags.js +26 -83
- package/dist/helpers/index.d.ts +16 -1
- package/dist/helpers/index.js +16 -1
- package/dist/helpers/lists.d.ts +28 -0
- package/dist/helpers/lists.js +65 -0
- package/dist/helpers/mailboxes.js +16 -9
- package/dist/helpers/mutes.d.ts +15 -0
- package/dist/helpers/mutes.js +24 -0
- package/dist/helpers/nip-19.d.ts +4 -0
- package/dist/helpers/nip-19.js +27 -0
- package/dist/helpers/picture-post.d.ts +4 -0
- package/dist/helpers/picture-post.js +6 -0
- package/dist/helpers/pointers.js +13 -17
- package/dist/helpers/profile.d.ts +6 -1
- package/dist/helpers/profile.js +4 -0
- package/dist/helpers/relays.d.ts +6 -3
- package/dist/helpers/relays.js +25 -18
- package/dist/helpers/share.d.ts +4 -0
- package/dist/helpers/share.js +12 -0
- package/dist/helpers/tags.d.ts +17 -0
- package/dist/helpers/tags.js +28 -6
- package/dist/helpers/threading.js +3 -3
- package/dist/helpers/url.d.ts +7 -0
- package/dist/helpers/url.js +27 -0
- package/dist/helpers/user-status.d.ts +18 -0
- package/dist/helpers/user-status.js +21 -0
- package/dist/observable/__tests__/claim-events.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-events.test.js +23 -0
- package/dist/observable/__tests__/claim-latest.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-latest.test.js +37 -0
- package/dist/observable/__tests__/simple-timeout.test.d.ts +1 -0
- package/dist/observable/__tests__/simple-timeout.test.js +34 -0
- package/dist/observable/claim-events.d.ts +5 -0
- package/dist/observable/claim-events.js +28 -0
- package/dist/observable/claim-latest.d.ts +5 -0
- package/dist/observable/claim-latest.js +21 -0
- package/dist/observable/{get-value.d.ts → get-observable-value.d.ts} +1 -1
- package/dist/observable/{get-value.js → get-observable-value.js} +3 -8
- package/dist/observable/index.d.ts +2 -1
- package/dist/observable/index.js +2 -1
- package/dist/observable/share-latest-value.d.ts +2 -4
- package/dist/observable/share-latest-value.js +19 -16
- package/dist/observable/simple-timeout.d.ts +4 -0
- package/dist/observable/simple-timeout.js +6 -0
- package/dist/observable/with-immediate-value.d.ts +3 -0
- package/dist/observable/with-immediate-value.js +19 -0
- package/dist/queries/blossom.d.ts +2 -0
- package/dist/queries/blossom.js +10 -0
- package/dist/queries/bookmarks.d.ts +8 -0
- package/dist/queries/bookmarks.js +23 -0
- package/dist/queries/channels.d.ts +11 -0
- package/dist/queries/channels.js +73 -0
- package/dist/queries/contacts.d.ts +3 -0
- package/dist/queries/contacts.js +12 -0
- package/dist/queries/index.d.ts +6 -0
- package/dist/queries/index.js +6 -0
- package/dist/queries/mutes.d.ts +8 -0
- package/dist/queries/mutes.js +23 -0
- package/dist/queries/pins.d.ts +3 -0
- package/dist/queries/pins.js +12 -0
- package/dist/queries/simple.d.ts +3 -3
- package/dist/queries/simple.js +3 -3
- package/dist/queries/thread.js +1 -1
- package/dist/queries/user-status.d.ts +11 -0
- package/dist/queries/user-status.js +39 -0
- package/dist/query-store/__tests__/query-store.test.d.ts +1 -0
- package/dist/query-store/__tests__/query-store.test.js +63 -0
- package/dist/query-store/index.d.ts +1 -57
- package/dist/query-store/index.js +1 -66
- package/dist/query-store/query-store.d.ts +53 -0
- package/dist/query-store/query-store.js +97 -0
- package/package.json +20 -8
- package/dist/helpers/media-attachment.d.ts +0 -33
- package/dist/helpers/media-attachment.js +0 -60
- /package/dist/{helpers/hidden-tags.test.d.ts → event-store/__tests__/event-store.test.d.ts} +0 -0
- /package/dist/{helpers/mailboxes.test.d.ts → event-store/interface.js} +0 -0
- /package/dist/helpers/{threading.test.d.ts → __tests__/blossom.test.d.ts} +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { verifyEvent } from "nostr-tools";
|
|
2
|
+
import { getHiddenContent, isHiddenContentLocked, unlockHiddenContent } from "./hidden-content.js";
|
|
3
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
4
|
+
export const GiftWrapSealSymbol = Symbol.for("gift-wrap-seal");
|
|
5
|
+
export const GiftWrapEventSymbol = Symbol.for("gift-wrap-event");
|
|
6
|
+
/** Returns the unsigned seal event in a gift-wrap event */
|
|
7
|
+
export function getGiftWrapSeal(gift) {
|
|
8
|
+
if (isHiddenContentLocked(gift))
|
|
9
|
+
return undefined;
|
|
10
|
+
return getOrComputeCachedValue(gift, GiftWrapSealSymbol, () => {
|
|
11
|
+
const plaintext = getHiddenContent(gift);
|
|
12
|
+
if (!plaintext)
|
|
13
|
+
throw new Error("Gift-wrap is locked");
|
|
14
|
+
const seal = JSON.parse(plaintext);
|
|
15
|
+
// verify the seal is valid
|
|
16
|
+
verifyEvent(seal);
|
|
17
|
+
return seal;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Returns the unsigned event in the gift-wrap seal */
|
|
21
|
+
export function getGiftWrapEvent(gift) {
|
|
22
|
+
if (isHiddenContentLocked(gift))
|
|
23
|
+
return undefined;
|
|
24
|
+
return getOrComputeCachedValue(gift, GiftWrapEventSymbol, () => {
|
|
25
|
+
const seal = getGiftWrapSeal(gift);
|
|
26
|
+
if (!seal)
|
|
27
|
+
throw new Error("Gift is locked");
|
|
28
|
+
const plaintext = getHiddenContent(seal);
|
|
29
|
+
if (!plaintext)
|
|
30
|
+
throw new Error("Gift-wrap seal is locked");
|
|
31
|
+
const event = JSON.parse(plaintext);
|
|
32
|
+
if (event.pubkey !== seal.pubkey)
|
|
33
|
+
throw new Error("Seal author does not match content");
|
|
34
|
+
return event;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
38
|
+
export function isGiftWrapLocked(gift) {
|
|
39
|
+
return isHiddenContentLocked(gift) || isHiddenContentLocked(getGiftWrapSeal(gift));
|
|
40
|
+
}
|
|
41
|
+
/** Unlocks and returns the unsigned seal event in a gift-wrap */
|
|
42
|
+
export async function unlockGiftWrap(gift, signer) {
|
|
43
|
+
if (isHiddenContentLocked(gift))
|
|
44
|
+
await unlockHiddenContent(gift, signer);
|
|
45
|
+
const seal = getGiftWrapSeal(gift);
|
|
46
|
+
if (isHiddenContentLocked(seal))
|
|
47
|
+
await unlockHiddenContent(seal, signer);
|
|
48
|
+
return getGiftWrapEvent(gift);
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
export declare const GROUPS_LIST_KIND = 10009;
|
|
3
|
+
export declare const GROUP_MESSAGE_KIND = 9;
|
|
4
|
+
/** NIP-29 group pointer */
|
|
5
|
+
export type GroupPointer = {
|
|
6
|
+
id: string;
|
|
7
|
+
relay: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* decodes a group identifier into a group pointer object
|
|
12
|
+
* @throws
|
|
13
|
+
*/
|
|
14
|
+
export declare function decodeGroupPointer(str: string): GroupPointer;
|
|
15
|
+
/** Converts a group pointer into a group identifier */
|
|
16
|
+
export declare function encodeGroupPointer(pointer: GroupPointer): string;
|
|
17
|
+
export declare const GroupsPublicSymbol: unique symbol;
|
|
18
|
+
export declare const GroupsHiddenSymbol: unique symbol;
|
|
19
|
+
/** gets a {@link GroupPointer} from a "group" tag */
|
|
20
|
+
export declare function getGroupPointerFromGroupTag(tag: string[]): GroupPointer;
|
|
21
|
+
/** Returns all the public groups from a k:10009 list */
|
|
22
|
+
export declare function getPublicGroups(bookmark: NostrEvent): GroupPointer[];
|
|
23
|
+
/** Returns all the hidden groups from a k:10009 list */
|
|
24
|
+
export declare function getHiddenGroups(bookmark: NostrEvent): GroupPointer[] | undefined;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
import { processTags } from "./tags.js";
|
|
3
|
+
import { getHiddenTags } from "./hidden-tags.js";
|
|
4
|
+
export const GROUPS_LIST_KIND = 10009;
|
|
5
|
+
export const GROUP_MESSAGE_KIND = 9;
|
|
6
|
+
/**
|
|
7
|
+
* decodes a group identifier into a group pointer object
|
|
8
|
+
* @throws
|
|
9
|
+
*/
|
|
10
|
+
export function decodeGroupPointer(str) {
|
|
11
|
+
const [relay, id] = str.split("'");
|
|
12
|
+
if (!relay)
|
|
13
|
+
throw new Error("Group pointer missing relay");
|
|
14
|
+
return { relay, id: id || "_" };
|
|
15
|
+
}
|
|
16
|
+
/** Converts a group pointer into a group identifier */
|
|
17
|
+
export function encodeGroupPointer(pointer) {
|
|
18
|
+
const hostname = URL.canParse(pointer.relay) ? new URL(pointer.relay).hostname : pointer.relay;
|
|
19
|
+
return `${hostname}'${pointer.id}`;
|
|
20
|
+
}
|
|
21
|
+
export const GroupsPublicSymbol = Symbol.for("groups-public");
|
|
22
|
+
export const GroupsHiddenSymbol = Symbol.for("groups-hidden");
|
|
23
|
+
/** gets a {@link GroupPointer} from a "group" tag */
|
|
24
|
+
export function getGroupPointerFromGroupTag(tag) {
|
|
25
|
+
const [_, id, relay, name] = tag;
|
|
26
|
+
return { id, relay, name };
|
|
27
|
+
}
|
|
28
|
+
/** Returns all the public groups from a k:10009 list */
|
|
29
|
+
export function getPublicGroups(bookmark) {
|
|
30
|
+
return getOrComputeCachedValue(bookmark, GroupsPublicSymbol, () => processTags(bookmark.tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag));
|
|
31
|
+
}
|
|
32
|
+
/** Returns all the hidden groups from a k:10009 list */
|
|
33
|
+
export function getHiddenGroups(bookmark) {
|
|
34
|
+
return getOrComputeCachedValue(bookmark, GroupsHiddenSymbol, () => {
|
|
35
|
+
const tags = getHiddenTags(bookmark);
|
|
36
|
+
return (tags &&
|
|
37
|
+
processTags(bookmark.tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag));
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export declare const HiddenContentSymbol: unique symbol;
|
|
2
|
+
export type HiddenContentSigner = {
|
|
3
|
+
nip04?: {
|
|
4
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
5
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
6
|
+
};
|
|
7
|
+
nip44?: {
|
|
8
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
9
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
/** Various event kinds that can have encrypted tags in their content and which encryption method they use */
|
|
13
|
+
export declare const EventContentEncryptionMethod: Record<number, "nip04" | "nip44">;
|
|
14
|
+
/** Sets the encryption method that is used for the contents of a specific event kind */
|
|
15
|
+
export declare function setEventContentEncryptionMethod(kind: number, method: "nip04" | "nip44"): void;
|
|
16
|
+
/** Checks if an event can have hidden content */
|
|
17
|
+
export declare function canHaveHiddenContent(kind: number): boolean;
|
|
18
|
+
/** Checks if an event has hidden content */
|
|
19
|
+
export declare function hasHiddenContent<T extends {
|
|
20
|
+
kind: number;
|
|
21
|
+
content: string;
|
|
22
|
+
}>(event: T): boolean;
|
|
23
|
+
/** Returns the hidden tags for an event if they are unlocked */
|
|
24
|
+
export declare function getHiddenContent<T extends object>(event: T): string | undefined;
|
|
25
|
+
/** Checks if the hidden tags are locked */
|
|
26
|
+
export declare function isHiddenContentLocked<T extends object>(event: T): boolean;
|
|
27
|
+
/** Returns either nip04 or nip44 encryption methods depending on event kind */
|
|
28
|
+
export declare function getHiddenContentEncryptionMethods(kind: number, signer: HiddenContentSigner): {
|
|
29
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
30
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
31
|
+
} | {
|
|
32
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
33
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
34
|
+
};
|
|
35
|
+
export type HiddenContentEvent = {
|
|
36
|
+
kind: number;
|
|
37
|
+
pubkey: string;
|
|
38
|
+
content: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Unlocks the encrypted content in an event
|
|
42
|
+
* @param event The event with content to decrypt
|
|
43
|
+
* @param signer A signer to use to decrypt the tags
|
|
44
|
+
* @throws
|
|
45
|
+
*/
|
|
46
|
+
export declare function unlockHiddenContent<T extends HiddenContentEvent>(event: T, signer: HiddenContentSigner): Promise<string>;
|
|
47
|
+
/** Removes the unencrypted hidden content on an event */
|
|
48
|
+
export declare function lockHiddenContent<T extends object>(event: T): void;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as kinds from "nostr-tools/kinds";
|
|
2
|
+
import { GROUPS_LIST_KIND } from "./groups.js";
|
|
3
|
+
import { getParentEventStore, isEvent } from "./event.js";
|
|
4
|
+
export const HiddenContentSymbol = Symbol.for("hidden-content");
|
|
5
|
+
/** Various event kinds that can have encrypted tags in their content and which encryption method they use */
|
|
6
|
+
export const EventContentEncryptionMethod = {
|
|
7
|
+
// NIP-60 wallet
|
|
8
|
+
17375: "nip44",
|
|
9
|
+
375: "nip44",
|
|
10
|
+
7375: "nip44",
|
|
11
|
+
7376: "nip44",
|
|
12
|
+
// DMs
|
|
13
|
+
[kinds.EncryptedDirectMessage]: "nip04",
|
|
14
|
+
// Gift wraps
|
|
15
|
+
[kinds.GiftWrap]: "nip44",
|
|
16
|
+
// NIP-51 lists
|
|
17
|
+
[kinds.BookmarkList]: "nip04",
|
|
18
|
+
[kinds.InterestsList]: "nip04",
|
|
19
|
+
[kinds.Mutelist]: "nip04",
|
|
20
|
+
[kinds.CommunitiesList]: "nip04",
|
|
21
|
+
[kinds.PublicChatsList]: "nip04",
|
|
22
|
+
[kinds.SearchRelaysList]: "nip04",
|
|
23
|
+
[GROUPS_LIST_KIND]: "nip04",
|
|
24
|
+
// NIP-51 sets
|
|
25
|
+
[kinds.Bookmarksets]: "nip04",
|
|
26
|
+
[kinds.Relaysets]: "nip04",
|
|
27
|
+
[kinds.Followsets]: "nip04",
|
|
28
|
+
[kinds.Curationsets]: "nip04",
|
|
29
|
+
[kinds.Interestsets]: "nip04",
|
|
30
|
+
};
|
|
31
|
+
/** Sets the encryption method that is used for the contents of a specific event kind */
|
|
32
|
+
export function setEventContentEncryptionMethod(kind, method) {
|
|
33
|
+
EventContentEncryptionMethod[kind] = method;
|
|
34
|
+
}
|
|
35
|
+
/** Checks if an event can have hidden content */
|
|
36
|
+
export function canHaveHiddenContent(kind) {
|
|
37
|
+
return EventContentEncryptionMethod[kind] !== undefined;
|
|
38
|
+
}
|
|
39
|
+
/** Checks if an event has hidden content */
|
|
40
|
+
export function hasHiddenContent(event) {
|
|
41
|
+
return canHaveHiddenContent(event.kind) && event.content.length > 0;
|
|
42
|
+
}
|
|
43
|
+
/** Returns the hidden tags for an event if they are unlocked */
|
|
44
|
+
export function getHiddenContent(event) {
|
|
45
|
+
return Reflect.get(event, HiddenContentSymbol);
|
|
46
|
+
}
|
|
47
|
+
/** Checks if the hidden tags are locked */
|
|
48
|
+
export function isHiddenContentLocked(event) {
|
|
49
|
+
return Reflect.has(event, HiddenContentSymbol) === false;
|
|
50
|
+
}
|
|
51
|
+
/** Returns either nip04 or nip44 encryption methods depending on event kind */
|
|
52
|
+
export function getHiddenContentEncryptionMethods(kind, signer) {
|
|
53
|
+
const method = EventContentEncryptionMethod[kind];
|
|
54
|
+
const encryption = signer[method];
|
|
55
|
+
if (!encryption)
|
|
56
|
+
throw new Error(`Signer does not support ${method} encryption`);
|
|
57
|
+
return encryption;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Unlocks the encrypted content in an event
|
|
61
|
+
* @param event The event with content to decrypt
|
|
62
|
+
* @param signer A signer to use to decrypt the tags
|
|
63
|
+
* @throws
|
|
64
|
+
*/
|
|
65
|
+
export async function unlockHiddenContent(event, signer) {
|
|
66
|
+
if (!canHaveHiddenContent(event.kind))
|
|
67
|
+
throw new Error("Event kind does not support hidden content");
|
|
68
|
+
const encryption = getHiddenContentEncryptionMethods(event.kind, signer);
|
|
69
|
+
const plaintext = await encryption.decrypt(event.pubkey, event.content);
|
|
70
|
+
Reflect.set(event, HiddenContentSymbol, plaintext);
|
|
71
|
+
// if the event has been added to an event store, notify it
|
|
72
|
+
if (isEvent(event)) {
|
|
73
|
+
const eventStore = getParentEventStore(event);
|
|
74
|
+
if (eventStore)
|
|
75
|
+
eventStore.update(event);
|
|
76
|
+
}
|
|
77
|
+
return plaintext;
|
|
78
|
+
}
|
|
79
|
+
/** Removes the unencrypted hidden content on an event */
|
|
80
|
+
export function lockHiddenContent(event) {
|
|
81
|
+
Reflect.deleteProperty(event, HiddenContentSymbol);
|
|
82
|
+
// if the event has been added to an event store, notify it
|
|
83
|
+
if (isEvent(event)) {
|
|
84
|
+
const eventStore = getParentEventStore(event);
|
|
85
|
+
if (eventStore)
|
|
86
|
+
eventStore.update(event);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { EventStore } from "applesauce-core";
|
|
3
|
-
export type HiddenTagsSigner = {
|
|
4
|
-
nip04?: {
|
|
5
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
6
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
7
|
-
};
|
|
8
|
-
nip44?: {
|
|
9
|
-
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
10
|
-
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
export type TagOperation = (tags: string[][]) => string[][];
|
|
1
|
+
import { HiddenContentEvent, HiddenContentSigner } from "./hidden-content.js";
|
|
14
2
|
export declare const HiddenTagsSymbol: unique symbol;
|
|
15
|
-
/** Various event kinds that can have encrypted tags in their content and which encryption method they use */
|
|
16
|
-
export declare const EventEncryptionMethod: Record<number, "nip04" | "nip44">;
|
|
17
3
|
/** Checks if an event can have hidden tags */
|
|
18
4
|
export declare function canHaveHiddenTags(kind: number): boolean;
|
|
19
5
|
/** Checks if an event has hidden tags */
|
|
20
|
-
export declare function hasHiddenTags
|
|
6
|
+
export declare function hasHiddenTags<T extends {
|
|
7
|
+
content: string;
|
|
8
|
+
kind: number;
|
|
9
|
+
}>(event: T): boolean;
|
|
21
10
|
/** Returns the hidden tags for an event if they are unlocked */
|
|
22
|
-
export declare function getHiddenTags(event:
|
|
11
|
+
export declare function getHiddenTags<T extends object>(event: T): string[][] | undefined;
|
|
23
12
|
/** Checks if the hidden tags are locked */
|
|
24
|
-
export declare function isHiddenTagsLocked(event:
|
|
13
|
+
export declare function isHiddenTagsLocked<T extends object>(event: T): boolean;
|
|
14
|
+
/** Returns either nip04 or nip44 encryption method depending on list kind */
|
|
15
|
+
export declare function getHiddenTagsEncryptionMethods(kind: number, signer: HiddenContentSigner): {
|
|
16
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
17
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
18
|
+
} | {
|
|
19
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
20
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
21
|
+
};
|
|
25
22
|
/**
|
|
26
23
|
* Decrypts the private list
|
|
27
24
|
* @param event The list event to decrypt
|
|
@@ -29,20 +26,5 @@ export declare function isHiddenTagsLocked(event: NostrEvent): boolean;
|
|
|
29
26
|
* @param store An optional EventStore to notify about the update
|
|
30
27
|
* @throws
|
|
31
28
|
*/
|
|
32
|
-
export declare function unlockHiddenTags(event:
|
|
33
|
-
|
|
34
|
-
* Modifies tags and returns an EventTemplate
|
|
35
|
-
* @param event Event to modify
|
|
36
|
-
* @param operations Operations for hidden and public tags
|
|
37
|
-
* @param signer A signer to use to decrypt the tags
|
|
38
|
-
* @throws
|
|
39
|
-
*/
|
|
40
|
-
export declare function modifyEventTags(event: NostrEvent | UnsignedEvent, operations: {
|
|
41
|
-
public?: TagOperation;
|
|
42
|
-
hidden?: TagOperation;
|
|
43
|
-
}, signer?: HiddenTagsSigner): Promise<EventTemplate>;
|
|
44
|
-
/**
|
|
45
|
-
* Override the hidden tags in an event
|
|
46
|
-
* @throws
|
|
47
|
-
*/
|
|
48
|
-
export declare function overrideHiddenTags(event: NostrEvent, hidden: string[][], signer: HiddenTagsSigner): Promise<EventTemplate>;
|
|
29
|
+
export declare function unlockHiddenTags<T extends HiddenContentEvent>(event: T, signer: HiddenContentSigner): Promise<string[][]>;
|
|
30
|
+
export declare function lockHiddenTags<T extends object>(event: T): void;
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { canHaveHiddenContent, getHiddenContent, getHiddenContentEncryptionMethods, isHiddenContentLocked, lockHiddenContent, unlockHiddenContent, } from "./hidden-content.js";
|
|
2
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
3
|
export const HiddenTagsSymbol = Symbol.for("hidden-tags");
|
|
4
|
-
/** Various event kinds that can have encrypted tags in their content and which encryption method they use */
|
|
5
|
-
export const EventEncryptionMethod = {
|
|
6
|
-
// NIP-60 wallet
|
|
7
|
-
37375: "nip44",
|
|
8
|
-
// NIP-51 lists
|
|
9
|
-
[kinds.BookmarkList]: "nip04",
|
|
10
|
-
[kinds.InterestsList]: "nip04",
|
|
11
|
-
[kinds.Mutelist]: "nip04",
|
|
12
|
-
[kinds.CommunitiesList]: "nip04",
|
|
13
|
-
[kinds.PublicChatsList]: "nip04",
|
|
14
|
-
[kinds.SearchRelaysList]: "nip04",
|
|
15
|
-
// NIP-51 sets
|
|
16
|
-
[kinds.Bookmarksets]: "nip04",
|
|
17
|
-
[kinds.Relaysets]: "nip04",
|
|
18
|
-
[kinds.Followsets]: "nip04",
|
|
19
|
-
[kinds.Curationsets]: "nip04",
|
|
20
|
-
[kinds.Interestsets]: "nip04",
|
|
21
|
-
};
|
|
22
4
|
/** Checks if an event can have hidden tags */
|
|
23
5
|
export function canHaveHiddenTags(kind) {
|
|
24
|
-
return
|
|
6
|
+
return canHaveHiddenContent(kind);
|
|
25
7
|
}
|
|
26
8
|
/** Checks if an event has hidden tags */
|
|
27
9
|
export function hasHiddenTags(event) {
|
|
@@ -29,18 +11,24 @@ export function hasHiddenTags(event) {
|
|
|
29
11
|
}
|
|
30
12
|
/** Returns the hidden tags for an event if they are unlocked */
|
|
31
13
|
export function getHiddenTags(event) {
|
|
32
|
-
|
|
14
|
+
if (isHiddenTagsLocked(event))
|
|
15
|
+
return undefined;
|
|
16
|
+
return getOrComputeCachedValue(event, HiddenTagsSymbol, () => {
|
|
17
|
+
const plaintext = getHiddenContent(event);
|
|
18
|
+
const parsed = JSON.parse(plaintext);
|
|
19
|
+
if (!Array.isArray(parsed))
|
|
20
|
+
throw new Error("Content is not an array of tags");
|
|
21
|
+
// Convert array to tags array string[][]
|
|
22
|
+
return parsed.filter((t) => Array.isArray(t)).map((t) => t.map((v) => String(v)));
|
|
23
|
+
});
|
|
33
24
|
}
|
|
34
25
|
/** Checks if the hidden tags are locked */
|
|
35
26
|
export function isHiddenTagsLocked(event) {
|
|
36
|
-
return
|
|
27
|
+
return isHiddenContentLocked(event);
|
|
37
28
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!encryption)
|
|
42
|
-
throw new Error(`Signer does not support ${method} encryption`);
|
|
43
|
-
return encryption;
|
|
29
|
+
/** Returns either nip04 or nip44 encryption method depending on list kind */
|
|
30
|
+
export function getHiddenTagsEncryptionMethods(kind, signer) {
|
|
31
|
+
return getHiddenContentEncryptionMethods(kind, signer);
|
|
44
32
|
}
|
|
45
33
|
/**
|
|
46
34
|
* Decrypts the private list
|
|
@@ -49,60 +37,15 @@ function getEventEncryption(kind, signer) {
|
|
|
49
37
|
* @param store An optional EventStore to notify about the update
|
|
50
38
|
* @throws
|
|
51
39
|
*/
|
|
52
|
-
export async function unlockHiddenTags(event, signer
|
|
40
|
+
export async function unlockHiddenTags(event, signer) {
|
|
53
41
|
if (!canHaveHiddenTags(event.kind))
|
|
54
42
|
throw new Error("Event kind does not support hidden tags");
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (store)
|
|
64
|
-
store.update(event);
|
|
65
|
-
return event;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Modifies tags and returns an EventTemplate
|
|
69
|
-
* @param event Event to modify
|
|
70
|
-
* @param operations Operations for hidden and public tags
|
|
71
|
-
* @param signer A signer to use to decrypt the tags
|
|
72
|
-
* @throws
|
|
73
|
-
*/
|
|
74
|
-
export async function modifyEventTags(event, operations, signer) {
|
|
75
|
-
const draft = { content: event.content, tags: event.tags, kind: event.kind, created_at: unixNow() };
|
|
76
|
-
if (operations.public) {
|
|
77
|
-
draft.tags = operations.public(event.tags);
|
|
78
|
-
}
|
|
79
|
-
if (operations.hidden) {
|
|
80
|
-
if (!signer)
|
|
81
|
-
throw new Error("Missing signer for hidden tags");
|
|
82
|
-
if (!canHaveHiddenTags(event.kind))
|
|
83
|
-
throw new Error("Event kind does not support hidden tags");
|
|
84
|
-
const hidden = hasHiddenTags(event) ? getHiddenTags(event) : [];
|
|
85
|
-
if (!hidden)
|
|
86
|
-
throw new Error("Hidden tags are locked");
|
|
87
|
-
const newHidden = operations.hidden(hidden);
|
|
88
|
-
const encryption = getEventEncryption(event.kind, signer);
|
|
89
|
-
draft.content = await encryption.encrypt(event.pubkey, JSON.stringify(newHidden));
|
|
90
|
-
}
|
|
91
|
-
return draft;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Override the hidden tags in an event
|
|
95
|
-
* @throws
|
|
96
|
-
*/
|
|
97
|
-
export async function overrideHiddenTags(event, hidden, signer) {
|
|
98
|
-
if (!canHaveHiddenTags(event.kind))
|
|
99
|
-
throw new Error("Event kind does not support hidden tags");
|
|
100
|
-
const encryption = getEventEncryption(event.kind, signer);
|
|
101
|
-
const ciphertext = await encryption.encrypt(event.pubkey, JSON.stringify(hidden));
|
|
102
|
-
return {
|
|
103
|
-
kind: event.kind,
|
|
104
|
-
content: ciphertext,
|
|
105
|
-
created_at: unixNow(),
|
|
106
|
-
tags: event.tags,
|
|
107
|
-
};
|
|
43
|
+
// unlock hidden content is needed
|
|
44
|
+
if (isHiddenContentLocked(event))
|
|
45
|
+
await unlockHiddenContent(event, signer);
|
|
46
|
+
return getHiddenTags(event);
|
|
47
|
+
}
|
|
48
|
+
export function lockHiddenTags(event) {
|
|
49
|
+
Reflect.deleteProperty(event, HiddenTagsSymbol);
|
|
50
|
+
lockHiddenContent(event);
|
|
108
51
|
}
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
+
export * from "./blossom.js";
|
|
1
2
|
export * from "./bolt11.js";
|
|
3
|
+
export * from "./bookmarks.js";
|
|
2
4
|
export * from "./cache.js";
|
|
5
|
+
export * from "./channels.js";
|
|
3
6
|
export * from "./comment.js";
|
|
7
|
+
export * from "./contacts.js";
|
|
4
8
|
export * from "./content.js";
|
|
5
9
|
export * from "./delete.js";
|
|
10
|
+
export * from "./direct-messages.js";
|
|
11
|
+
export * from "./dns-identity.js";
|
|
6
12
|
export * from "./emoji.js";
|
|
7
13
|
export * from "./event.js";
|
|
8
14
|
export * from "./external-id.js";
|
|
15
|
+
export * from "./file-metadata.js";
|
|
9
16
|
export * from "./filter.js";
|
|
17
|
+
export * from "./gift-wraps.js";
|
|
18
|
+
export * from "./groups.js";
|
|
10
19
|
export * from "./hashtag.js";
|
|
20
|
+
export * from "./hidden-content.js";
|
|
11
21
|
export * from "./hidden-tags.js";
|
|
22
|
+
export * from "./json.js";
|
|
23
|
+
export * from "./lists.js";
|
|
12
24
|
export * from "./lnurl.js";
|
|
13
25
|
export * from "./lru.js";
|
|
14
26
|
export * from "./mailboxes.js";
|
|
15
|
-
export * from "./
|
|
27
|
+
export * from "./mutes.js";
|
|
28
|
+
export * from "./picture-post.js";
|
|
16
29
|
export * from "./pointers.js";
|
|
17
30
|
export * from "./profile.js";
|
|
18
31
|
export * from "./relays.js";
|
|
32
|
+
export * from "./share.js";
|
|
19
33
|
export * from "./string.js";
|
|
20
34
|
export * from "./tags.js";
|
|
21
35
|
export * from "./threading.js";
|
|
22
36
|
export * from "./time.js";
|
|
23
37
|
export * from "./url.js";
|
|
38
|
+
export * from "./user-status.js";
|
|
24
39
|
export * from "./zap.js";
|
package/dist/helpers/index.js
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
+
export * from "./blossom.js";
|
|
1
2
|
export * from "./bolt11.js";
|
|
3
|
+
export * from "./bookmarks.js";
|
|
2
4
|
export * from "./cache.js";
|
|
5
|
+
export * from "./channels.js";
|
|
3
6
|
export * from "./comment.js";
|
|
7
|
+
export * from "./contacts.js";
|
|
4
8
|
export * from "./content.js";
|
|
5
9
|
export * from "./delete.js";
|
|
10
|
+
export * from "./direct-messages.js";
|
|
11
|
+
export * from "./dns-identity.js";
|
|
6
12
|
export * from "./emoji.js";
|
|
7
13
|
export * from "./event.js";
|
|
8
14
|
export * from "./external-id.js";
|
|
15
|
+
export * from "./file-metadata.js";
|
|
9
16
|
export * from "./filter.js";
|
|
17
|
+
export * from "./gift-wraps.js";
|
|
18
|
+
export * from "./groups.js";
|
|
10
19
|
export * from "./hashtag.js";
|
|
20
|
+
export * from "./hidden-content.js";
|
|
11
21
|
export * from "./hidden-tags.js";
|
|
22
|
+
export * from "./json.js";
|
|
23
|
+
export * from "./lists.js";
|
|
12
24
|
export * from "./lnurl.js";
|
|
13
25
|
export * from "./lru.js";
|
|
14
26
|
export * from "./mailboxes.js";
|
|
15
|
-
export * from "./
|
|
27
|
+
export * from "./mutes.js";
|
|
28
|
+
export * from "./picture-post.js";
|
|
16
29
|
export * from "./pointers.js";
|
|
17
30
|
export * from "./profile.js";
|
|
18
31
|
export * from "./relays.js";
|
|
32
|
+
export * from "./share.js";
|
|
19
33
|
export * from "./string.js";
|
|
20
34
|
export * from "./tags.js";
|
|
21
35
|
export * from "./threading.js";
|
|
22
36
|
export * from "./time.js";
|
|
23
37
|
export * from "./url.js";
|
|
38
|
+
export * from "./user-status.js";
|
|
24
39
|
export * from "./zap.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AddressPointer, EventPointer, ProfilePointer } from "nostr-tools/nip19";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
/**
|
|
4
|
+
* Checks if an event pointer is anywhere in a list or set
|
|
5
|
+
* NOTE: Ignores the `relay` field in EventPointer
|
|
6
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
7
|
+
*/
|
|
8
|
+
export declare function isEventPointerInList(list: NostrEvent, pointer: string | EventPointer): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if an address pointer is anywhere in a list or set
|
|
11
|
+
* NOTE: Ignores the `relay` field in AddressPointer
|
|
12
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
13
|
+
*/
|
|
14
|
+
export declare function isAddressPointerInList(list: NostrEvent, pointer: string | AddressPointer): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Checks if an profile pointer is anywhere in a list or set
|
|
17
|
+
* NOTE: Ignores the `relay` field in ProfilePointer
|
|
18
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
19
|
+
*/
|
|
20
|
+
export declare function isProfilePointerInList(list: NostrEvent, pointer: string | ProfilePointer): boolean;
|
|
21
|
+
/** Returns all the EventPointer in a list or set */
|
|
22
|
+
export declare function getEventPointersFromList(list: NostrEvent): EventPointer[];
|
|
23
|
+
/** Returns all the AddressPointer in a list or set */
|
|
24
|
+
export declare function getAddressPointersFromList(list: NostrEvent): AddressPointer[];
|
|
25
|
+
/** Returns all the ProfilePointer in a list or set */
|
|
26
|
+
export declare function getProfilePointersFromList(list: NostrEvent): ProfilePointer[];
|
|
27
|
+
/** Returns if an event is a valid list or set */
|
|
28
|
+
export declare function isValidList(event: NostrEvent): boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { isParameterizedReplaceableKind, isReplaceableKind } from "nostr-tools/kinds";
|
|
2
|
+
import { getHiddenTags } from "./hidden-tags.js";
|
|
3
|
+
import { getAddressPointerFromATag, getCoordinateFromAddressPointer, getEventPointerFromETag, getProfilePointerFromPTag, } from "./pointers.js";
|
|
4
|
+
import { isATag, isETag, isPTag, processTags } from "./tags.js";
|
|
5
|
+
import { getReplaceableIdentifier } from "./event.js";
|
|
6
|
+
function listGetAllTags(list) {
|
|
7
|
+
const hidden = getHiddenTags(list);
|
|
8
|
+
return hidden ? [...hidden, ...list.tags] : list.tags;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Checks if an event pointer is anywhere in a list or set
|
|
12
|
+
* NOTE: Ignores the `relay` field in EventPointer
|
|
13
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
14
|
+
*/
|
|
15
|
+
export function isEventPointerInList(list, pointer) {
|
|
16
|
+
const id = typeof pointer === "string" ? pointer : pointer.id;
|
|
17
|
+
return listGetAllTags(list).some((t) => t[0] === "e" && t[1] === id);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Checks if an address pointer is anywhere in a list or set
|
|
21
|
+
* NOTE: Ignores the `relay` field in AddressPointer
|
|
22
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
23
|
+
*/
|
|
24
|
+
export function isAddressPointerInList(list, pointer) {
|
|
25
|
+
const cord = typeof pointer === "string" ? pointer : getCoordinateFromAddressPointer(pointer);
|
|
26
|
+
return listGetAllTags(list).some((t) => t[0] === "a" && t[1] === cord);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks if an profile pointer is anywhere in a list or set
|
|
30
|
+
* NOTE: Ignores the `relay` field in ProfilePointer
|
|
31
|
+
* NOTE: This will check the hidden tags if the list has hidden tags and they are unlocked
|
|
32
|
+
*/
|
|
33
|
+
export function isProfilePointerInList(list, pointer) {
|
|
34
|
+
const pubkey = typeof pointer === "string" ? pointer : pointer.pubkey;
|
|
35
|
+
return listGetAllTags(list).some((t) => t[0] === "p" && t[1] === pubkey);
|
|
36
|
+
}
|
|
37
|
+
/** Returns all the EventPointer in a list or set */
|
|
38
|
+
export function getEventPointersFromList(list) {
|
|
39
|
+
return processTags(listGetAllTags(list), (tag) => (isETag(tag) ? tag : undefined), getEventPointerFromETag);
|
|
40
|
+
}
|
|
41
|
+
/** Returns all the AddressPointer in a list or set */
|
|
42
|
+
export function getAddressPointersFromList(list) {
|
|
43
|
+
return processTags(listGetAllTags(list), (t) => (isATag(t) ? t : undefined), getAddressPointerFromATag);
|
|
44
|
+
}
|
|
45
|
+
/** Returns all the ProfilePointer in a list or set */
|
|
46
|
+
export function getProfilePointersFromList(list) {
|
|
47
|
+
return processTags(listGetAllTags(list), (t) => (isPTag(t) ? t : undefined), getProfilePointerFromPTag);
|
|
48
|
+
}
|
|
49
|
+
/** Returns if an event is a valid list or set */
|
|
50
|
+
export function isValidList(event) {
|
|
51
|
+
try {
|
|
52
|
+
if (isParameterizedReplaceableKind(event.kind)) {
|
|
53
|
+
// event is a set
|
|
54
|
+
// ensure the set has an identifier
|
|
55
|
+
getReplaceableIdentifier(event);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
else if (isReplaceableKind(event.kind) && event.kind >= 10000 && event.kind < 20000) {
|
|
59
|
+
// event is a list
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) { }
|
|
64
|
+
return false;
|
|
65
|
+
}
|