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.
- package/dist/event-store/async-event-store.d.ts +134 -0
- package/dist/event-store/async-event-store.js +349 -0
- package/dist/event-store/{event-set.d.ts → event-memory.d.ts} +15 -25
- package/dist/event-store/{event-set.js → event-memory.js} +43 -53
- package/dist/event-store/event-store.d.ts +57 -63
- package/dist/event-store/event-store.js +111 -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 +111 -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 +1 -1
- package/dist/helpers/pointers.js +2 -1
- package/dist/helpers/profile.d.ts +7 -3
- package/dist/helpers/profile.js +7 -8
- package/dist/helpers/relay-selection.d.ts +13 -0
- package/dist/helpers/relay-selection.js +84 -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 +16 -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 +7 -0
- package/dist/observable/relay-selection.js +38 -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,7 +1,7 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
2
|
import { catchError, combineLatest, distinct, EMPTY, filter, isObservable, map, merge, mergeMap, of, switchMap, } from "rxjs";
|
|
3
3
|
import { logger } from "../logger.js";
|
|
4
|
-
import { canHaveEncryptedContent, getEncryptedContent,
|
|
4
|
+
import { canHaveEncryptedContent, getEncryptedContent, isEncryptedContentUnlocked, setEncryptedContentCache, } from "./encrypted-content.js";
|
|
5
5
|
import { notifyEventUpdate } from "./event.js";
|
|
6
6
|
import { getGiftWrapSeal, getSealGiftWrap, getSealRumor } from "./gift-wraps.js";
|
|
7
7
|
/** A symbol that is used to mark encrypted content as being from a cache */
|
|
@@ -32,7 +32,7 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
32
32
|
const restore = eventStore.insert$
|
|
33
33
|
.pipe(
|
|
34
34
|
// Look for events that support encrypted content and are locked
|
|
35
|
-
filter((e) => canHaveEncryptedContent(e.kind) &&
|
|
35
|
+
filter((e) => canHaveEncryptedContent(e.kind) && isEncryptedContentUnlocked(e) === false),
|
|
36
36
|
// Get the encrypted content from storage
|
|
37
37
|
mergeMap((event) =>
|
|
38
38
|
// Wait for storage to be available
|
|
@@ -52,11 +52,11 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
52
52
|
const restoreSeals = eventStore.update$
|
|
53
53
|
.pipe(
|
|
54
54
|
// Look for gift wraps that are unlocked
|
|
55
|
-
filter((e) => e.kind === kinds.GiftWrap &&
|
|
55
|
+
filter((e) => e.kind === kinds.GiftWrap && isEncryptedContentUnlocked(e)),
|
|
56
56
|
// Get the seal event
|
|
57
57
|
map((gift) => getGiftWrapSeal(gift)),
|
|
58
58
|
// Look for gift wraps with locked seals
|
|
59
|
-
filter((seal) => seal !== undefined &&
|
|
59
|
+
filter((seal) => seal !== undefined && isEncryptedContentUnlocked(seal) === false),
|
|
60
60
|
// Only attempt to unlock seals once
|
|
61
61
|
distinct((seal) => seal.id),
|
|
62
62
|
// Get encrypted content from storage
|
|
@@ -84,7 +84,7 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
84
84
|
.pipe(
|
|
85
85
|
// Look for events that support encrypted content and are unlocked and not from the cache
|
|
86
86
|
filter(([event]) => canHaveEncryptedContent(event.kind) &&
|
|
87
|
-
|
|
87
|
+
isEncryptedContentUnlocked(event) &&
|
|
88
88
|
!isEncryptedContentFromCache(event)),
|
|
89
89
|
// Only persist the encrypted content once
|
|
90
90
|
distinct(([event]) => event.id))
|
|
@@ -106,13 +106,13 @@ export function persistEncryptedContent(eventStore, storage, fallback) {
|
|
|
106
106
|
const persistSeals = combineLatest([merge(eventStore.update$, eventStore.insert$), storage$])
|
|
107
107
|
.pipe(
|
|
108
108
|
// Look for gift wraps that are unlocked
|
|
109
|
-
filter(([event]) => event.kind === kinds.GiftWrap &&
|
|
109
|
+
filter(([event]) => event.kind === kinds.GiftWrap && isEncryptedContentUnlocked(event)),
|
|
110
110
|
// Get the seal event
|
|
111
111
|
map(([gift, storage]) => [getGiftWrapSeal(gift), storage]),
|
|
112
112
|
// Make sure the seal is defined
|
|
113
113
|
filter(([seal]) => seal !== undefined),
|
|
114
114
|
// Make sure seal is unlocked and not from cache
|
|
115
|
-
filter(([seal]) =>
|
|
115
|
+
filter(([seal]) => isEncryptedContentUnlocked(seal) && !isEncryptedContentFromCache(seal)),
|
|
116
116
|
// Only persist the seal once
|
|
117
117
|
distinct(([seal]) => seal.id))
|
|
118
118
|
.subscribe(async ([seal, storage]) => {
|
|
@@ -10,7 +10,12 @@ export interface EncryptedContentSigner {
|
|
|
10
10
|
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
+
/** Encryption method types */
|
|
13
14
|
export type EncryptionMethod = "nip04" | "nip44";
|
|
15
|
+
/** Type for an event who's encrypted content is unlocked */
|
|
16
|
+
export type UnlockedEncryptedContent = {
|
|
17
|
+
[EncryptedContentSymbol]: string;
|
|
18
|
+
};
|
|
14
19
|
/** A pair of encryption methods for encrypting and decrypting event content */
|
|
15
20
|
export interface EncryptionMethods {
|
|
16
21
|
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
@@ -37,14 +42,16 @@ export declare function hasEncryptedContent<T extends {
|
|
|
37
42
|
content: string;
|
|
38
43
|
}>(event: T): boolean;
|
|
39
44
|
/** Returns the encrypted content for an event if it is unlocked */
|
|
45
|
+
export declare function getEncryptedContent<T extends UnlockedEncryptedContent>(event: T): string;
|
|
40
46
|
export declare function getEncryptedContent<T extends object>(event: T): string | undefined;
|
|
41
|
-
/** Checks if the encrypted content is
|
|
42
|
-
export declare function
|
|
47
|
+
/** Checks if the encrypted content is unlocked and casts it to the {@link UnlockedEncryptedContent} type */
|
|
48
|
+
export declare function isEncryptedContentUnlocked<T extends object>(event: T): event is T & UnlockedEncryptedContent;
|
|
43
49
|
/**
|
|
44
50
|
* Unlocks the encrypted content in an event and caches it
|
|
45
51
|
* @param event The event with content to decrypt
|
|
46
52
|
* @param pubkey The other pubkey that encrypted the content
|
|
47
53
|
* @param signer A signer to use to decrypt the content
|
|
54
|
+
* @throws If the event kind does not support encrypted content
|
|
48
55
|
*/
|
|
49
56
|
export declare function unlockEncryptedContent<T extends {
|
|
50
57
|
kind: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
|
-
import {
|
|
2
|
+
import { notifyEventUpdate } from "./event.js";
|
|
3
3
|
/** A symbol use to store the encrypted content of an event in memory */
|
|
4
4
|
export const EncryptedContentSymbol = Symbol.for("encrypted-content");
|
|
5
5
|
/** Various event kinds that can have encrypted content and which encryption method they use */
|
|
@@ -39,37 +39,40 @@ export function canHaveEncryptedContent(kind) {
|
|
|
39
39
|
export function hasEncryptedContent(event) {
|
|
40
40
|
return event.content.length > 0;
|
|
41
41
|
}
|
|
42
|
-
/** Returns the encrypted content for an event if it is unlocked */
|
|
43
42
|
export function getEncryptedContent(event) {
|
|
44
43
|
return Reflect.get(event, EncryptedContentSymbol);
|
|
45
44
|
}
|
|
46
|
-
/** Checks if the encrypted content is
|
|
47
|
-
export function
|
|
48
|
-
return Reflect.has(event, EncryptedContentSymbol) ===
|
|
45
|
+
/** Checks if the encrypted content is unlocked and casts it to the {@link UnlockedEncryptedContent} type */
|
|
46
|
+
export function isEncryptedContentUnlocked(event) {
|
|
47
|
+
return Reflect.has(event, EncryptedContentSymbol) === true;
|
|
49
48
|
}
|
|
50
49
|
/**
|
|
51
50
|
* Unlocks the encrypted content in an event and caches it
|
|
52
51
|
* @param event The event with content to decrypt
|
|
53
52
|
* @param pubkey The other pubkey that encrypted the content
|
|
54
53
|
* @param signer A signer to use to decrypt the content
|
|
54
|
+
* @throws If the event kind does not support encrypted content
|
|
55
55
|
*/
|
|
56
56
|
export async function unlockEncryptedContent(event, pubkey, signer) {
|
|
57
|
+
if (!canHaveEncryptedContent(event.kind))
|
|
58
|
+
throw new Error("Event kind does not support encrypted content");
|
|
59
|
+
// Get the encryption methods from the signer
|
|
57
60
|
const encryption = getEncryptedContentEncryptionMethods(event.kind, signer);
|
|
58
61
|
const plaintext = await encryption.decrypt(pubkey, event.content);
|
|
62
|
+
// Set the cached value and trigger update
|
|
59
63
|
setEncryptedContentCache(event, plaintext);
|
|
64
|
+
// Return the decrypted content
|
|
60
65
|
return plaintext;
|
|
61
66
|
}
|
|
62
67
|
/** Sets the encrypted content on an event and updates it if its part of an event store */
|
|
63
68
|
export function setEncryptedContentCache(event, plaintext) {
|
|
64
69
|
Reflect.set(event, EncryptedContentSymbol, plaintext);
|
|
65
70
|
// if the event has been added to an event store, notify it
|
|
66
|
-
|
|
67
|
-
notifyEventUpdate(event);
|
|
71
|
+
notifyEventUpdate(event);
|
|
68
72
|
}
|
|
69
73
|
/** Removes the encrypted content cache on an event */
|
|
70
74
|
export function lockEncryptedContent(event) {
|
|
71
75
|
Reflect.deleteProperty(event, EncryptedContentSymbol);
|
|
72
76
|
// if the event has been added to an event store, notify it
|
|
73
|
-
|
|
74
|
-
notifyEventUpdate(event);
|
|
77
|
+
notifyEventUpdate(event);
|
|
75
78
|
}
|
|
@@ -9,7 +9,9 @@ import { IEventStoreStreams } from "../event-store/interface.js";
|
|
|
9
9
|
* @param opts.maxBatchSize - The maximum number of events to write in a batch
|
|
10
10
|
* @returns A function to stop the process
|
|
11
11
|
*/
|
|
12
|
-
export declare function
|
|
12
|
+
export declare function persistEventsToCache(eventStore: IEventStoreStreams, write: (events: NostrEvent[]) => Promise<void>, opts?: {
|
|
13
13
|
maxBatchSize?: number;
|
|
14
14
|
batchTime?: number;
|
|
15
15
|
}): () => void;
|
|
16
|
+
/** @deprecated Use persistEventsToCache instead */
|
|
17
|
+
export declare const presistEventsToCache: typeof persistEventsToCache;
|
|
@@ -11,7 +11,7 @@ const log = logger.extend("event-cache");
|
|
|
11
11
|
* @param opts.maxBatchSize - The maximum number of events to write in a batch
|
|
12
12
|
* @returns A function to stop the process
|
|
13
13
|
*/
|
|
14
|
-
export function
|
|
14
|
+
export function persistEventsToCache(eventStore, write, opts) {
|
|
15
15
|
const time = opts?.batchTime ?? 5_000;
|
|
16
16
|
// Save all new events to the cache
|
|
17
17
|
const sub = eventStore.insert$
|
|
@@ -30,3 +30,5 @@ export function presistEventsToCache(eventStore, write, opts) {
|
|
|
30
30
|
});
|
|
31
31
|
return () => sub.unsubscribe();
|
|
32
32
|
}
|
|
33
|
+
/** @deprecated Use persistEventsToCache instead */
|
|
34
|
+
export const presistEventsToCache = persistEventsToCache;
|
|
@@ -10,5 +10,11 @@ export declare function getTagValue<T extends {
|
|
|
10
10
|
tags: string[][];
|
|
11
11
|
content: string;
|
|
12
12
|
}>(event: T, name: string): string | undefined;
|
|
13
|
+
/** Checks if an event has a public name / value tag*/
|
|
14
|
+
export declare function hasNameValueTag<T extends {
|
|
15
|
+
kind: number;
|
|
16
|
+
tags: string[][];
|
|
17
|
+
content: string;
|
|
18
|
+
}>(event: T, name: string, value: string): boolean;
|
|
13
19
|
/** Returns a Set of tag names and values that are indexable */
|
|
14
20
|
export declare function getIndexableTags(event: NostrEvent): Set<string>;
|
|
@@ -13,6 +13,10 @@ export function getTagValue(event, name) {
|
|
|
13
13
|
return hiddenValue;
|
|
14
14
|
return event.tags.find((t) => t[0] === name)?.[1];
|
|
15
15
|
}
|
|
16
|
+
/** Checks if an event has a public name / value tag*/
|
|
17
|
+
export function hasNameValueTag(event, name, value) {
|
|
18
|
+
return event.tags.some((t) => t[0] === name && t[1] === value);
|
|
19
|
+
}
|
|
16
20
|
/** Returns a Set of tag names and values that are indexable */
|
|
17
21
|
export function getIndexableTags(event) {
|
|
18
22
|
let indexable = Reflect.get(event, EventIndexableTagsSymbol);
|
package/dist/helpers/event.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { NostrEvent, VerifiedEvent } from "nostr-tools";
|
|
2
2
|
import { IEventStore } from "../event-store/interface.js";
|
|
3
|
+
export { NostrEvent, EventTemplate, UnsignedEvent, verifiedSymbol, verifyEvent, VerifiedEvent } from "nostr-tools/pure";
|
|
4
|
+
export { bytesToHex, hexToBytes, insertEventIntoAscendingList, insertEventIntoDescendingList, binarySearch, } from "nostr-tools/utils";
|
|
5
|
+
export * as kinds from "nostr-tools/kinds";
|
|
6
|
+
/** An event with a known kind. this is used to know if events have been validated */
|
|
7
|
+
export type KnownEvent<K extends number> = Omit<NostrEvent, "kind"> & {
|
|
8
|
+
kind: K;
|
|
9
|
+
};
|
|
3
10
|
/** A symbol on an event that marks which event store its part of */
|
|
4
11
|
export declare const EventStoreSymbol: unique symbol;
|
|
5
12
|
export declare const EventUIDSymbol: unique symbol;
|
|
@@ -38,7 +45,7 @@ export declare function isFromCache(event: NostrEvent): boolean;
|
|
|
38
45
|
/** Returns the EventStore of an event if its been added to one */
|
|
39
46
|
export declare function getParentEventStore<T extends object>(event: T): IEventStore | undefined;
|
|
40
47
|
/** Notifies the events parent store that an event has been updated */
|
|
41
|
-
export declare function notifyEventUpdate(event:
|
|
48
|
+
export declare function notifyEventUpdate(event: any): void;
|
|
42
49
|
/** Returns the replaceable identifier for a replaceable event */
|
|
43
50
|
export declare function getReplaceableIdentifier(event: NostrEvent): string;
|
|
44
51
|
/** Checks if an event is a NIP-70 protected event */
|
package/dist/helpers/event.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { verifiedSymbol } from "nostr-tools";
|
|
2
2
|
import { isAddressableKind, isReplaceableKind } from "nostr-tools/kinds";
|
|
3
3
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
4
|
+
// Re-export types from nostr-tools
|
|
5
|
+
export { verifiedSymbol, verifyEvent } from "nostr-tools/pure";
|
|
6
|
+
export { bytesToHex, hexToBytes, insertEventIntoAscendingList, insertEventIntoDescendingList, binarySearch, } from "nostr-tools/utils";
|
|
7
|
+
export * as kinds from "nostr-tools/kinds";
|
|
4
8
|
/** A symbol on an event that marks which event store its part of */
|
|
5
9
|
export const EventStoreSymbol = Symbol.for("event-store");
|
|
6
10
|
export const EventUIDSymbol = Symbol.for("event-uid");
|
|
@@ -81,6 +85,8 @@ export function getParentEventStore(event) {
|
|
|
81
85
|
}
|
|
82
86
|
/** Notifies the events parent store that an event has been updated */
|
|
83
87
|
export function notifyEventUpdate(event) {
|
|
88
|
+
if (!isEvent(event))
|
|
89
|
+
return;
|
|
84
90
|
const eventStore = getParentEventStore(event);
|
|
85
91
|
if (eventStore)
|
|
86
92
|
eventStore.update(event);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NostrEvent } from "nostr-tools";
|
|
2
2
|
export type FileMetadata = {
|
|
3
3
|
/** URL of the file */
|
|
4
|
-
url
|
|
4
|
+
url?: string;
|
|
5
5
|
/** MIME type */
|
|
6
6
|
type?: string;
|
|
7
7
|
/** sha256 hash of the file */
|
|
@@ -32,24 +32,19 @@ export type FileMetadata = {
|
|
|
32
32
|
/** fallback URLs */
|
|
33
33
|
fallback?: string[];
|
|
34
34
|
};
|
|
35
|
+
/** Alias for {@link FileMetadata} */
|
|
35
36
|
export type MediaAttachment = FileMetadata;
|
|
36
37
|
/**
|
|
37
38
|
* Parses file metadata tags into {@link FileMetadata}
|
|
38
39
|
* @throws
|
|
39
40
|
*/
|
|
40
41
|
export declare function parseFileMetadataTags(tags: string[][]): FileMetadata;
|
|
41
|
-
/**
|
|
42
|
-
* Parses a imeta tag into a {@link FileMetadata}
|
|
43
|
-
* @throws
|
|
44
|
-
*/
|
|
42
|
+
/** Parses a imeta tag into a {@link FileMetadata} */
|
|
45
43
|
export declare function getFileMetadataFromImetaTag(tag: string[]): FileMetadata;
|
|
46
44
|
export declare const MediaAttachmentsSymbol: unique symbol;
|
|
47
45
|
/** Gets all the media attachments on an event */
|
|
48
46
|
export declare function getMediaAttachments(event: NostrEvent): FileMetadata[];
|
|
49
|
-
/**
|
|
50
|
-
* Gets {@link FileMetadata} for a NIP-94 kind 1063 event
|
|
51
|
-
* @throws
|
|
52
|
-
*/
|
|
47
|
+
/** Gets {@link FileMetadata} for a NIP-94 kind 1063 event */
|
|
53
48
|
export declare function getFileMetadata(file: NostrEvent): FileMetadata;
|
|
54
49
|
/** Returns the last 64 length hex string in a URL */
|
|
55
50
|
export declare function getSha256FromURL(url: string | URL): string | undefined;
|
|
@@ -16,8 +16,6 @@ export function parseFileMetadataTags(tags) {
|
|
|
16
16
|
break;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
if (!fields.url)
|
|
20
|
-
throw new Error("Missing required url in file metadata");
|
|
21
19
|
const metadata = { url: fields.url, fallback };
|
|
22
20
|
// parse size
|
|
23
21
|
if (fields.size)
|
|
@@ -47,10 +45,7 @@ export function parseFileMetadataTags(tags) {
|
|
|
47
45
|
metadata.blurhash = fields.blurhash;
|
|
48
46
|
return metadata;
|
|
49
47
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Parses a imeta tag into a {@link FileMetadata}
|
|
52
|
-
* @throws
|
|
53
|
-
*/
|
|
48
|
+
/** Parses a imeta tag into a {@link FileMetadata} */
|
|
54
49
|
export function getFileMetadataFromImetaTag(tag) {
|
|
55
50
|
const parts = tag.slice(1);
|
|
56
51
|
const tags = [];
|
|
@@ -81,10 +76,7 @@ export function getMediaAttachments(event) {
|
|
|
81
76
|
.filter((a) => !!a);
|
|
82
77
|
});
|
|
83
78
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Gets {@link FileMetadata} for a NIP-94 kind 1063 event
|
|
86
|
-
* @throws
|
|
87
|
-
*/
|
|
79
|
+
/** Gets {@link FileMetadata} for a NIP-94 kind 1063 event */
|
|
88
80
|
export function getFileMetadata(file) {
|
|
89
81
|
return parseFileMetadataTags(file.tags);
|
|
90
82
|
}
|
package/dist/helpers/filter.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Filter, NostrEvent } from "nostr-tools";
|
|
2
|
+
export { Filter } from "nostr-tools/filter";
|
|
2
3
|
/**
|
|
3
|
-
* Copied from nostr-tools and modified to use getIndexableTags
|
|
4
|
+
* Copied from nostr-tools and modified to use {@link getIndexableTags}
|
|
4
5
|
* @see https://github.com/nbd-wtf/nostr-tools/blob/a61cde77eacc9518001f11d7f67f1a50ae05fd80/filter.ts
|
|
5
6
|
*/
|
|
6
7
|
export declare function matchFilter(filter: Filter, event: NostrEvent): boolean;
|
|
7
|
-
/** Copied from nostr-tools */
|
|
8
|
+
/** Copied from nostr-tools and modified to use {@link matchFilter} */
|
|
8
9
|
export declare function matchFilters(filters: Filter[], event: NostrEvent): boolean;
|
|
9
|
-
/** Copied from nostr-tools and modified to support undefined
|
|
10
|
+
/** Copied from nostr-tools and modified to support undefined values */
|
|
10
11
|
export declare function mergeFilters(...filters: Filter[]): Filter;
|
|
11
12
|
/** Check if two filters are equal */
|
|
12
13
|
export declare function isFilterEqual(a: Filter | Filter[], b: Filter | Filter[]): boolean;
|
package/dist/helpers/filter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import equal from "fast-deep-equal";
|
|
2
2
|
import { getIndexableTags } from "./event-tags.js";
|
|
3
3
|
/**
|
|
4
|
-
* Copied from nostr-tools and modified to use getIndexableTags
|
|
4
|
+
* Copied from nostr-tools and modified to use {@link getIndexableTags}
|
|
5
5
|
* @see https://github.com/nbd-wtf/nostr-tools/blob/a61cde77eacc9518001f11d7f67f1a50ae05fd80/filter.ts
|
|
6
6
|
*/
|
|
7
7
|
export function matchFilter(filter, event) {
|
|
@@ -31,7 +31,7 @@ export function matchFilter(filter, event) {
|
|
|
31
31
|
return false;
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
34
|
-
/** Copied from nostr-tools */
|
|
34
|
+
/** Copied from nostr-tools and modified to use {@link matchFilter} */
|
|
35
35
|
export function matchFilters(filters, event) {
|
|
36
36
|
for (let i = 0; i < filters.length; i++) {
|
|
37
37
|
if (matchFilter(filters[i], event)) {
|
|
@@ -40,7 +40,7 @@ export function matchFilters(filters, event) {
|
|
|
40
40
|
}
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
|
-
/** Copied from nostr-tools and modified to support undefined
|
|
43
|
+
/** Copied from nostr-tools and modified to support undefined values */
|
|
44
44
|
export function mergeFilters(...filters) {
|
|
45
45
|
let result = {};
|
|
46
46
|
for (let i = 0; i < filters.length; i++) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { NostrEvent, UnsignedEvent } from "nostr-tools";
|
|
2
|
-
import {
|
|
1
|
+
import { kinds, NostrEvent, UnsignedEvent } from "nostr-tools";
|
|
2
|
+
import { EventMemory } from "../event-store/event-memory.js";
|
|
3
3
|
import { EncryptedContentSigner } from "./encrypted-content.js";
|
|
4
|
+
import { KnownEvent } from "./event.js";
|
|
4
5
|
/**
|
|
5
6
|
* An internal event set to keep track of seals and rumors
|
|
6
|
-
* This is
|
|
7
|
+
* This is intentionally isolated from the main applications event store so to prevent seals and rumors from being leaked
|
|
7
8
|
*/
|
|
8
|
-
export declare const internalGiftWrapEvents:
|
|
9
|
+
export declare const internalGiftWrapEvents: EventMemory;
|
|
9
10
|
export type Rumor = UnsignedEvent & {
|
|
10
11
|
id: string;
|
|
11
12
|
};
|
|
@@ -15,24 +16,43 @@ export declare const SealSymbol: unique symbol;
|
|
|
15
16
|
export declare const RumorSymbol: unique symbol;
|
|
16
17
|
/** Used to store a reference to the parent gift wrap event on seals (upstream) */
|
|
17
18
|
export declare const GiftWrapSymbol: unique symbol;
|
|
19
|
+
/** A gift wrap event that knows its seal event */
|
|
20
|
+
export type UnlockedGiftWrapEvent = KnownEvent<kinds.GiftWrap> & {
|
|
21
|
+
/** Downstream seal event */
|
|
22
|
+
[SealSymbol]: UnlockedSeal;
|
|
23
|
+
};
|
|
24
|
+
/** A seal that knows its parent gift wrap event */
|
|
25
|
+
export type UnlockedSeal = KnownEvent<kinds.Seal> & {
|
|
26
|
+
/** Upstream gift wrap event */
|
|
27
|
+
[SealSymbol]: UnlockedGiftWrapEvent;
|
|
28
|
+
/** Downstream rumor event */
|
|
29
|
+
[RumorSymbol]: Rumor;
|
|
30
|
+
};
|
|
18
31
|
/** Checks if an event is a rumor (normal event with "id" and no "sig") */
|
|
19
32
|
export declare function isRumor(event: any): event is Rumor;
|
|
20
33
|
/** Returns all the parent gift wraps for a seal event */
|
|
21
|
-
export declare function getSealGiftWrap(seal:
|
|
34
|
+
export declare function getSealGiftWrap(seal: UnlockedSeal): UnlockedGiftWrapEvent;
|
|
35
|
+
export declare function getSealGiftWrap(seal: NostrEvent): UnlockedGiftWrapEvent | undefined;
|
|
22
36
|
/** Returns all the parent seals for a rumor event */
|
|
23
|
-
export declare function getRumorSeals(rumor: Rumor):
|
|
37
|
+
export declare function getRumorSeals(rumor: Rumor): UnlockedSeal[];
|
|
24
38
|
/** Returns all the parent gift wraps for a rumor event */
|
|
25
|
-
export declare function getRumorGiftWraps(rumor: Rumor):
|
|
26
|
-
/** Checks if a seal event is locked */
|
|
27
|
-
export declare function
|
|
28
|
-
/**
|
|
39
|
+
export declare function getRumorGiftWraps(rumor: Rumor): UnlockedGiftWrapEvent[];
|
|
40
|
+
/** Checks if a seal event is locked and casts it to the {@link UnlockedSeal} type */
|
|
41
|
+
export declare function isSealUnlocked(seal: NostrEvent): seal is UnlockedSeal;
|
|
42
|
+
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
43
|
+
export declare function isGiftWrapUnlocked(gift: NostrEvent): gift is UnlockedGiftWrapEvent;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the rumor from a seal event
|
|
46
|
+
* @throws {Error} If the author of the rumor event does not match the author of the seal
|
|
47
|
+
*/
|
|
48
|
+
export declare function getSealRumor(seal: UnlockedSeal): Rumor;
|
|
29
49
|
export declare function getSealRumor(seal: NostrEvent): Rumor | undefined;
|
|
30
|
-
/** Returns the seal event in a gift-wrap
|
|
50
|
+
/** Returns the seal event in a gift-wrap -> seal (downstream) */
|
|
51
|
+
export declare function getGiftWrapSeal(gift: UnlockedGiftWrapEvent): UnlockedSeal;
|
|
31
52
|
export declare function getGiftWrapSeal(gift: NostrEvent): NostrEvent | undefined;
|
|
32
|
-
/** Returns the unsigned rumor in the gift-wrap */
|
|
53
|
+
/** Returns the unsigned rumor in the gift-wrap -> seal -> rumor (downstream) */
|
|
54
|
+
export declare function getGiftWrapRumor(gift: UnlockedGiftWrapEvent): Rumor;
|
|
33
55
|
export declare function getGiftWrapRumor(gift: NostrEvent): Rumor | undefined;
|
|
34
|
-
/** Returns if a gift-wrap event or gift-wrap seal is locked */
|
|
35
|
-
export declare function isGiftWrapLocked(gift: NostrEvent): boolean;
|
|
36
56
|
/**
|
|
37
57
|
* Unlocks a seal event and returns the rumor event
|
|
38
58
|
* @throws {Error} If the author of the rumor event does not match the author of the seal
|
|
@@ -43,4 +63,5 @@ export declare function unlockSeal(seal: NostrEvent, signer: EncryptedContentSig
|
|
|
43
63
|
* @throws {Error} If the author of the rumor event does not match the author of the seal
|
|
44
64
|
*/
|
|
45
65
|
export declare function unlockGiftWrap(gift: NostrEvent, signer: EncryptedContentSigner): Promise<Rumor>;
|
|
66
|
+
/** Locks a gift-wrap event and seals its seal event */
|
|
46
67
|
export declare function lockGiftWrap(gift: NostrEvent): void;
|
|
@@ -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}`;
|