applesauce-core 0.0.0-next-20241204152949 → 0.0.0-next-20241205190859
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/event-store.d.ts +13 -5
- package/dist/event-store/event-store.js +31 -22
- package/dist/helpers/emoji.d.ts +2 -1
- package/dist/helpers/emoji.js +1 -0
- package/dist/helpers/event.d.ts +5 -0
- package/dist/helpers/event.js +16 -0
- package/dist/helpers/hidden-tags.d.ts +13 -4
- package/dist/helpers/hidden-tags.js +43 -25
- package/dist/helpers/pointers.d.ts +5 -1
- package/dist/helpers/pointers.js +9 -5
- package/dist/helpers/tags.d.ts +6 -0
- package/dist/helpers/tags.js +6 -0
- package/dist/helpers/url.d.ts +4 -1
- package/dist/helpers/url.js +4 -3
- package/dist/helpers/zap.d.ts +17 -0
- package/dist/helpers/zap.js +17 -0
- package/dist/observable/get-value.d.ts +1 -0
- package/dist/observable/get-value.js +1 -0
- package/dist/promise/deferred.d.ts +1 -0
- package/dist/promise/deferred.js +1 -0
- package/dist/queries/mailboxes.d.ts +1 -0
- package/dist/queries/mailboxes.js +1 -0
- package/dist/queries/profile.d.ts +1 -0
- package/dist/queries/profile.js +1 -0
- package/dist/queries/reactions.d.ts +1 -1
- package/dist/queries/reactions.js +1 -1
- package/dist/queries/simple.js +0 -2
- package/dist/queries/thread.d.ts +2 -0
- package/dist/queries/thread.js +28 -3
- package/dist/queries/zaps.d.ts +1 -0
- package/dist/queries/zaps.js +1 -0
- package/dist/query-store/index.d.ts +18 -10
- package/dist/query-store/index.js +33 -34
- package/package.json +1 -1
|
@@ -3,15 +3,19 @@ import { Observable } from "rxjs";
|
|
|
3
3
|
import { Database } from "./database.js";
|
|
4
4
|
export declare class EventStore {
|
|
5
5
|
database: Database;
|
|
6
|
-
/**
|
|
6
|
+
/** Enable this to keep old versions of replaceable events */
|
|
7
7
|
keepOldVersions: boolean;
|
|
8
8
|
constructor();
|
|
9
|
-
/** Adds an event to the database */
|
|
9
|
+
/** Adds an event to the database and update subscriptions */
|
|
10
10
|
add(event: NostrEvent, fromRelay?: string): NostrEvent;
|
|
11
|
+
/** Removes an event from the database and updates subscriptions */
|
|
12
|
+
remove(event: string | NostrEvent): boolean;
|
|
11
13
|
protected deletedIds: Set<string>;
|
|
12
14
|
protected deletedCoords: Map<string, number>;
|
|
13
15
|
protected handleDeleteEvent(deleteEvent: NostrEvent): void;
|
|
14
16
|
protected checkDeleted(event: NostrEvent): boolean;
|
|
17
|
+
/** Removes any event that is not being used by a subscription */
|
|
18
|
+
prune(max?: number): number;
|
|
15
19
|
/** Add an event to the store and notifies all subscribes it has updated */
|
|
16
20
|
update(event: NostrEvent): NostrEvent;
|
|
17
21
|
getAll(filters: Filter[]): Set<NostrEvent>;
|
|
@@ -34,8 +38,12 @@ export declare class EventStore {
|
|
|
34
38
|
pubkey: string;
|
|
35
39
|
identifier?: string;
|
|
36
40
|
}[]): Observable<Map<string, NostrEvent>>;
|
|
37
|
-
/**
|
|
38
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Creates an observable that streams all events that match the filter
|
|
43
|
+
* @param filters
|
|
44
|
+
* @param [onlyNew=false] Only subscribe to new events
|
|
45
|
+
*/
|
|
46
|
+
stream(filters: Filter | Filter[], onlyNew?: boolean): Observable<NostrEvent>;
|
|
39
47
|
/** Creates an observable that updates with an array of sorted events */
|
|
40
|
-
timeline(filters: Filter[], keepOldVersions?: boolean): Observable<NostrEvent[]>;
|
|
48
|
+
timeline(filters: Filter | Filter[], keepOldVersions?: boolean): Observable<NostrEvent[]>;
|
|
41
49
|
}
|
|
@@ -9,12 +9,12 @@ import { addSeenRelay } from "../helpers/relays.js";
|
|
|
9
9
|
import { getDeleteCoordinates, getDeleteIds } from "../helpers/delete.js";
|
|
10
10
|
export class EventStore {
|
|
11
11
|
database;
|
|
12
|
-
/**
|
|
12
|
+
/** Enable this to keep old versions of replaceable events */
|
|
13
13
|
keepOldVersions = false;
|
|
14
14
|
constructor() {
|
|
15
15
|
this.database = new Database();
|
|
16
16
|
}
|
|
17
|
-
/** Adds an event to the database */
|
|
17
|
+
/** Adds an event to the database and update subscriptions */
|
|
18
18
|
add(event, fromRelay) {
|
|
19
19
|
if (event.kind === kinds.EventDeletion)
|
|
20
20
|
this.handleDeleteEvent(event);
|
|
@@ -40,6 +40,16 @@ export class EventStore {
|
|
|
40
40
|
addSeenRelay(inserted, fromRelay);
|
|
41
41
|
return inserted;
|
|
42
42
|
}
|
|
43
|
+
/** Removes an event from the database and updates subscriptions */
|
|
44
|
+
remove(event) {
|
|
45
|
+
if (typeof event === "string")
|
|
46
|
+
return this.database.deleteEvent(event);
|
|
47
|
+
else if (this.database.hasEvent(event.id)) {
|
|
48
|
+
return this.database.deleteEvent(event.id);
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
43
53
|
deletedIds = new Set();
|
|
44
54
|
deletedCoords = new Map();
|
|
45
55
|
handleDeleteEvent(deleteEvent) {
|
|
@@ -70,6 +80,10 @@ export class EventStore {
|
|
|
70
80
|
}
|
|
71
81
|
return false;
|
|
72
82
|
}
|
|
83
|
+
/** Removes any event that is not being used by a subscription */
|
|
84
|
+
prune(max) {
|
|
85
|
+
return this.database.prune(max);
|
|
86
|
+
}
|
|
73
87
|
/** Add an event to the store and notifies all subscribes it has updated */
|
|
74
88
|
update(event) {
|
|
75
89
|
return this.database.updateEvent(event);
|
|
@@ -282,35 +296,30 @@ export class EventStore {
|
|
|
282
296
|
};
|
|
283
297
|
});
|
|
284
298
|
}
|
|
285
|
-
/**
|
|
286
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Creates an observable that streams all events that match the filter
|
|
301
|
+
* @param filters
|
|
302
|
+
* @param [onlyNew=false] Only subscribe to new events
|
|
303
|
+
*/
|
|
304
|
+
stream(filters, onlyNew = false) {
|
|
305
|
+
filters = Array.isArray(filters) ? filters : [filters];
|
|
287
306
|
return new Observable((observer) => {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
this.database.claimEvent(event, observer);
|
|
293
|
-
claimed.add(event);
|
|
307
|
+
if (!onlyNew) {
|
|
308
|
+
let events = this.database.getForFilters(filters);
|
|
309
|
+
for (const event of events)
|
|
310
|
+
observer.next(event);
|
|
294
311
|
}
|
|
295
312
|
// subscribe to future events
|
|
296
313
|
const sub = this.database.inserted.subscribe((event) => {
|
|
297
|
-
if (matchFilters(filters, event))
|
|
314
|
+
if (matchFilters(filters, event))
|
|
298
315
|
observer.next(event);
|
|
299
|
-
this.database.claimEvent(event, observer);
|
|
300
|
-
claimed.add(event);
|
|
301
|
-
}
|
|
302
316
|
});
|
|
303
|
-
return () =>
|
|
304
|
-
sub.unsubscribe();
|
|
305
|
-
// remove all claims
|
|
306
|
-
for (const event of claimed)
|
|
307
|
-
this.database.removeClaim(event, observer);
|
|
308
|
-
claimed.clear();
|
|
309
|
-
};
|
|
317
|
+
return () => sub.unsubscribe();
|
|
310
318
|
});
|
|
311
319
|
}
|
|
312
320
|
/** Creates an observable that updates with an array of sorted events */
|
|
313
|
-
timeline(filters, keepOldVersions =
|
|
321
|
+
timeline(filters, keepOldVersions = false) {
|
|
322
|
+
filters = Array.isArray(filters) ? filters : [filters];
|
|
314
323
|
return new Observable((observer) => {
|
|
315
324
|
const seen = new Map();
|
|
316
325
|
const timeline = [];
|
package/dist/helpers/emoji.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventTemplate, NostrEvent } from "nostr-tools";
|
|
2
|
-
|
|
2
|
+
/** Gets an "emoji" tag that matches an emoji code */
|
|
3
|
+
export declare function getEmojiTag(event: NostrEvent | EventTemplate, code: string): ["emoji", string, string] | undefined;
|
|
3
4
|
/** Returns the name of a NIP-30 emoji pack */
|
|
4
5
|
export declare function getPackName(pack: NostrEvent): string | undefined;
|
|
5
6
|
/** Returns an array of emojis from a NIP-30 emoji pack */
|
package/dist/helpers/emoji.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getTagValue } from "./event.js";
|
|
2
|
+
/** Gets an "emoji" tag that matches an emoji code */
|
|
2
3
|
export function getEmojiTag(event, code) {
|
|
3
4
|
code = code.replace(/^:|:$/g, "").toLocaleLowerCase();
|
|
4
5
|
return event.tags.filter((t) => t[0] === "emoji" && t[1] && t[2]).find((t) => t[1].toLowerCase() === code);
|
package/dist/helpers/event.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ declare module "nostr-tools" {
|
|
|
9
9
|
[FromCacheSymbol]?: boolean;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Checks if an object is a nostr event
|
|
14
|
+
* NOTE: does not validation the signature on the event
|
|
15
|
+
*/
|
|
16
|
+
export declare function isEvent(event: any): event is NostrEvent;
|
|
12
17
|
/**
|
|
13
18
|
* Returns if a kind is replaceable ( 10000 <= n < 20000 || n == 0 || n == 3 )
|
|
14
19
|
* or parameterized replaceable ( 30000 <= n < 40000 )
|
package/dist/helpers/event.js
CHANGED
|
@@ -4,6 +4,22 @@ import { getHiddenTags } from "./hidden-tags.js";
|
|
|
4
4
|
export const EventUIDSymbol = Symbol.for("event-uid");
|
|
5
5
|
export const EventIndexableTagsSymbol = Symbol.for("indexable-tags");
|
|
6
6
|
export const FromCacheSymbol = Symbol.for("from-cache");
|
|
7
|
+
/**
|
|
8
|
+
* Checks if an object is a nostr event
|
|
9
|
+
* NOTE: does not validation the signature on the event
|
|
10
|
+
*/
|
|
11
|
+
export function isEvent(event) {
|
|
12
|
+
if (event === undefined || event === null)
|
|
13
|
+
return false;
|
|
14
|
+
return (event.id?.length === 64 &&
|
|
15
|
+
typeof event.sig === "string" &&
|
|
16
|
+
typeof event.pubkey === "string" &&
|
|
17
|
+
event.pubkey.length === 64 &&
|
|
18
|
+
typeof event.content === "string" &&
|
|
19
|
+
Array.isArray(event.tags) &&
|
|
20
|
+
typeof event.created_at === "number" &&
|
|
21
|
+
event.created_at > 0);
|
|
22
|
+
}
|
|
7
23
|
/**
|
|
8
24
|
* Returns if a kind is replaceable ( 10000 <= n < 20000 || n == 0 || n == 3 )
|
|
9
25
|
* or parameterized replaceable ( 30000 <= n < 40000 )
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
import { EventTemplate, NostrEvent, UnsignedEvent } from "nostr-tools";
|
|
2
2
|
import { EventStore } from "applesauce-core";
|
|
3
3
|
export type HiddenTagsSigner = {
|
|
4
|
-
nip04
|
|
4
|
+
nip04?: {
|
|
5
|
+
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
6
|
+
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
7
|
+
};
|
|
8
|
+
nip44?: {
|
|
5
9
|
encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
|
|
6
10
|
decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
|
|
7
11
|
};
|
|
8
12
|
};
|
|
9
13
|
export type TagOperation = (tags: string[][]) => string[][];
|
|
10
14
|
export declare const HiddenTagsSymbol: unique symbol;
|
|
11
|
-
|
|
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">;
|
|
12
17
|
/** Checks if an event can have hidden tags */
|
|
13
|
-
export declare function canHaveHiddenTags(
|
|
18
|
+
export declare function canHaveHiddenTags(kind: number): boolean;
|
|
14
19
|
/** Checks if an event has hidden tags */
|
|
15
20
|
export declare function hasHiddenTags(event: NostrEvent | EventTemplate): boolean;
|
|
16
|
-
/** Returns the hidden tags
|
|
21
|
+
/** Returns the hidden tags for an event if they are unlocked */
|
|
17
22
|
export declare function getHiddenTags(event: NostrEvent | EventTemplate): string[][] | undefined;
|
|
23
|
+
/** Checks if the hidden tags are locked */
|
|
18
24
|
export declare function isHiddenTagsLocked(event: NostrEvent): boolean;
|
|
19
25
|
/**
|
|
20
26
|
* Decrypts the private list
|
|
21
27
|
* @param event The list event to decrypt
|
|
22
28
|
* @param signer A signer to use to decrypt the tags
|
|
23
29
|
* @param store An optional EventStore to notify about the update
|
|
30
|
+
* @throws
|
|
24
31
|
*/
|
|
25
32
|
export declare function unlockHiddenTags(event: NostrEvent, signer: HiddenTagsSigner, store?: EventStore): Promise<NostrEvent>;
|
|
26
33
|
/**
|
|
@@ -28,6 +35,7 @@ export declare function unlockHiddenTags(event: NostrEvent, signer: HiddenTagsSi
|
|
|
28
35
|
* @param event Event to modify
|
|
29
36
|
* @param operations Operations for hidden and public tags
|
|
30
37
|
* @param signer A signer to use to decrypt the tags
|
|
38
|
+
* @throws
|
|
31
39
|
*/
|
|
32
40
|
export declare function modifyEventTags(event: NostrEvent | UnsignedEvent, operations: {
|
|
33
41
|
public?: TagOperation;
|
|
@@ -35,5 +43,6 @@ export declare function modifyEventTags(event: NostrEvent | UnsignedEvent, opera
|
|
|
35
43
|
}, signer?: HiddenTagsSigner): Promise<EventTemplate>;
|
|
36
44
|
/**
|
|
37
45
|
* Override the hidden tags in an event
|
|
46
|
+
* @throws
|
|
38
47
|
*/
|
|
39
48
|
export declare function overrideHiddenTags(event: NostrEvent, hidden: string[][], signer: HiddenTagsSigner): Promise<EventTemplate>;
|
|
@@ -1,47 +1,59 @@
|
|
|
1
1
|
import { unixNow } from "applesauce-core/helpers";
|
|
2
2
|
import { kinds } from "nostr-tools";
|
|
3
3
|
export const HiddenTagsSymbol = Symbol.for("hidden-tags");
|
|
4
|
-
|
|
5
|
-
|
|
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",
|
|
6
8
|
// NIP-51 lists
|
|
7
|
-
kinds.BookmarkList,
|
|
8
|
-
kinds.InterestsList,
|
|
9
|
-
kinds.Mutelist,
|
|
10
|
-
kinds.CommunitiesList,
|
|
11
|
-
kinds.PublicChatsList,
|
|
12
|
-
kinds.SearchRelaysList,
|
|
13
|
-
kinds.SearchRelaysList,
|
|
14
|
-
10009, // NIP-29 groups
|
|
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
15
|
// NIP-51 sets
|
|
16
|
-
kinds.Bookmarksets,
|
|
17
|
-
kinds.Relaysets,
|
|
18
|
-
kinds.Followsets,
|
|
19
|
-
kinds.Curationsets,
|
|
20
|
-
kinds.Interestsets,
|
|
21
|
-
|
|
16
|
+
[kinds.Bookmarksets]: "nip04",
|
|
17
|
+
[kinds.Relaysets]: "nip04",
|
|
18
|
+
[kinds.Followsets]: "nip04",
|
|
19
|
+
[kinds.Curationsets]: "nip04",
|
|
20
|
+
[kinds.Interestsets]: "nip04",
|
|
21
|
+
};
|
|
22
22
|
/** Checks if an event can have hidden tags */
|
|
23
|
-
export function canHaveHiddenTags(
|
|
24
|
-
return
|
|
23
|
+
export function canHaveHiddenTags(kind) {
|
|
24
|
+
return EventEncryptionMethod[kind] !== undefined;
|
|
25
25
|
}
|
|
26
26
|
/** Checks if an event has hidden tags */
|
|
27
27
|
export function hasHiddenTags(event) {
|
|
28
|
-
return canHaveHiddenTags(event) && event.content.length > 0;
|
|
28
|
+
return canHaveHiddenTags(event.kind) && event.content.length > 0;
|
|
29
29
|
}
|
|
30
|
-
/** Returns the hidden tags
|
|
30
|
+
/** Returns the hidden tags for an event if they are unlocked */
|
|
31
31
|
export function getHiddenTags(event) {
|
|
32
32
|
return Reflect.get(event, HiddenTagsSymbol);
|
|
33
33
|
}
|
|
34
|
+
/** Checks if the hidden tags are locked */
|
|
34
35
|
export function isHiddenTagsLocked(event) {
|
|
35
36
|
return hasHiddenTags(event) && getHiddenTags(event) === undefined;
|
|
36
37
|
}
|
|
38
|
+
function getEventEncryption(kind, signer) {
|
|
39
|
+
const method = EventEncryptionMethod[kind];
|
|
40
|
+
const encryption = signer[method];
|
|
41
|
+
if (!encryption)
|
|
42
|
+
throw new Error(`Signer does not support ${method} encryption`);
|
|
43
|
+
return encryption;
|
|
44
|
+
}
|
|
37
45
|
/**
|
|
38
46
|
* Decrypts the private list
|
|
39
47
|
* @param event The list event to decrypt
|
|
40
48
|
* @param signer A signer to use to decrypt the tags
|
|
41
49
|
* @param store An optional EventStore to notify about the update
|
|
50
|
+
* @throws
|
|
42
51
|
*/
|
|
43
52
|
export async function unlockHiddenTags(event, signer, store) {
|
|
44
|
-
|
|
53
|
+
if (!canHaveHiddenTags(event.kind))
|
|
54
|
+
throw new Error("Event kind does not support hidden tags");
|
|
55
|
+
const encryption = getEventEncryption(event.kind, signer);
|
|
56
|
+
const plaintext = await encryption.decrypt(event.pubkey, event.content);
|
|
45
57
|
const parsed = JSON.parse(plaintext);
|
|
46
58
|
if (!Array.isArray(parsed))
|
|
47
59
|
throw new Error("Content is not an array of tags");
|
|
@@ -57,6 +69,7 @@ export async function unlockHiddenTags(event, signer, store) {
|
|
|
57
69
|
* @param event Event to modify
|
|
58
70
|
* @param operations Operations for hidden and public tags
|
|
59
71
|
* @param signer A signer to use to decrypt the tags
|
|
72
|
+
* @throws
|
|
60
73
|
*/
|
|
61
74
|
export async function modifyEventTags(event, operations, signer) {
|
|
62
75
|
const draft = { content: event.content, tags: event.tags, kind: event.kind, created_at: unixNow() };
|
|
@@ -66,21 +79,26 @@ export async function modifyEventTags(event, operations, signer) {
|
|
|
66
79
|
if (operations.hidden) {
|
|
67
80
|
if (!signer)
|
|
68
81
|
throw new Error("Missing signer for hidden tags");
|
|
69
|
-
if (!canHaveHiddenTags(event))
|
|
70
|
-
throw new Error("Event
|
|
82
|
+
if (!canHaveHiddenTags(event.kind))
|
|
83
|
+
throw new Error("Event kind does not support hidden tags");
|
|
71
84
|
const hidden = hasHiddenTags(event) ? getHiddenTags(event) : [];
|
|
72
85
|
if (!hidden)
|
|
73
86
|
throw new Error("Hidden tags are locked");
|
|
74
87
|
const newHidden = operations.hidden(hidden);
|
|
75
|
-
|
|
88
|
+
const encryption = getEventEncryption(event.kind, signer);
|
|
89
|
+
draft.content = await encryption.encrypt(event.pubkey, JSON.stringify(newHidden));
|
|
76
90
|
}
|
|
77
91
|
return draft;
|
|
78
92
|
}
|
|
79
93
|
/**
|
|
80
94
|
* Override the hidden tags in an event
|
|
95
|
+
* @throws
|
|
81
96
|
*/
|
|
82
97
|
export async function overrideHiddenTags(event, hidden, signer) {
|
|
83
|
-
|
|
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));
|
|
84
102
|
return {
|
|
85
103
|
kind: event.kind,
|
|
86
104
|
content: ciphertext,
|
|
@@ -15,13 +15,17 @@ export declare function parseCoordinate(a: string, requireD: false, silent: true
|
|
|
15
15
|
export declare function getPubkeyFromDecodeResult(result?: DecodeResult): string | undefined;
|
|
16
16
|
/** Encodes the result of nip19.decode */
|
|
17
17
|
export declare function encodeDecodeResult(result: DecodeResult): "" | `nprofile1${string}` | `nevent1${string}` | `naddr1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
|
|
18
|
+
/** @throws */
|
|
18
19
|
export declare function getEventPointerFromTag(tag: string[]): EventPointer;
|
|
20
|
+
/** @throws */
|
|
19
21
|
export declare function getAddressPointerFromTag(tag: string[]): AddressPointer;
|
|
22
|
+
/** @throws */
|
|
20
23
|
export declare function getProfilePointerFromTag(tag: string[]): ProfilePointer;
|
|
21
|
-
/** Parses a
|
|
24
|
+
/** Parses "e", "a", "p", and "q" tags into a pointer */
|
|
22
25
|
export declare function getPointerFromTag(tag: string[]): DecodeResult | null;
|
|
23
26
|
export declare function isAddressPointer(pointer: DecodeResult["data"]): pointer is AddressPointer;
|
|
24
27
|
export declare function isEventPointer(pointer: DecodeResult["data"]): pointer is EventPointer;
|
|
28
|
+
/** Returns the coordinate string for an AddressPointer */
|
|
25
29
|
export declare function getCoordinateFromAddressPointer(pointer: AddressPointer): string;
|
|
26
30
|
/** Returns a tag for an address pointer */
|
|
27
31
|
export declare function getATagFromAddressPointer(pointer: AddressPointer): ["a", ...string[]];
|
package/dist/helpers/pointers.js
CHANGED
|
@@ -65,6 +65,7 @@ export function encodeDecodeResult(result) {
|
|
|
65
65
|
}
|
|
66
66
|
return "";
|
|
67
67
|
}
|
|
68
|
+
/** @throws */
|
|
68
69
|
export function getEventPointerFromTag(tag) {
|
|
69
70
|
if (!tag[1])
|
|
70
71
|
throw new Error("Missing event id in tag");
|
|
@@ -76,6 +77,7 @@ export function getEventPointerFromTag(tag) {
|
|
|
76
77
|
pointer.author = tag[3];
|
|
77
78
|
return pointer;
|
|
78
79
|
}
|
|
80
|
+
/** @throws */
|
|
79
81
|
export function getAddressPointerFromTag(tag) {
|
|
80
82
|
if (!tag[1])
|
|
81
83
|
throw new Error("Missing coordinate in tag");
|
|
@@ -84,6 +86,7 @@ export function getAddressPointerFromTag(tag) {
|
|
|
84
86
|
pointer.relays = safeRelayUrls([tag[2]]);
|
|
85
87
|
return pointer;
|
|
86
88
|
}
|
|
89
|
+
/** @throws */
|
|
87
90
|
export function getProfilePointerFromTag(tag) {
|
|
88
91
|
if (!tag[1])
|
|
89
92
|
throw new Error("Missing pubkey in tag");
|
|
@@ -92,7 +95,7 @@ export function getProfilePointerFromTag(tag) {
|
|
|
92
95
|
pointer.relays = safeRelayUrls([tag[2]]);
|
|
93
96
|
return pointer;
|
|
94
97
|
}
|
|
95
|
-
/** Parses a
|
|
98
|
+
/** Parses "e", "a", "p", and "q" tags into a pointer */
|
|
96
99
|
export function getPointerFromTag(tag) {
|
|
97
100
|
try {
|
|
98
101
|
switch (tag[0]) {
|
|
@@ -115,13 +118,14 @@ export function getPointerFromTag(tag) {
|
|
|
115
118
|
}
|
|
116
119
|
export function isAddressPointer(pointer) {
|
|
117
120
|
return (typeof pointer !== "string" &&
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
Reflect.has(pointer, "identifier") &&
|
|
122
|
+
Reflect.has(pointer, "pubkey") &&
|
|
123
|
+
Reflect.has(pointer, "kind"));
|
|
121
124
|
}
|
|
122
125
|
export function isEventPointer(pointer) {
|
|
123
|
-
return typeof pointer !== "string" &&
|
|
126
|
+
return typeof pointer !== "string" && Reflect.has(pointer, "id");
|
|
124
127
|
}
|
|
128
|
+
/** Returns the coordinate string for an AddressPointer */
|
|
125
129
|
export function getCoordinateFromAddressPointer(pointer) {
|
|
126
130
|
return `${pointer.kind}:${pointer.pubkey}:${pointer.identifier}`;
|
|
127
131
|
}
|
package/dist/helpers/tags.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
/** Checks if tag is an "e" tag and has at least one value */
|
|
1
2
|
export declare function isETag(tag: string[]): tag is ["e", string, ...string[]];
|
|
3
|
+
/** Checks if tag is an "p" tag and has at least one value */
|
|
2
4
|
export declare function isPTag(tag: string[]): tag is ["p", string, ...string[]];
|
|
5
|
+
/** Checks if tag is an "r" tag and has at least one value */
|
|
3
6
|
export declare function isRTag(tag: string[]): tag is ["r", string, ...string[]];
|
|
7
|
+
/** Checks if tag is an "d" tag and has at least one value */
|
|
4
8
|
export declare function isDTag(tag: string[]): tag is ["d", string, ...string[]];
|
|
9
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
5
10
|
export declare function isATag(tag: string[]): tag is ["a", string, ...string[]];
|
|
11
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
6
12
|
export declare function isTTag(tag: string[]): tag is ["t", string, ...string[]];
|
package/dist/helpers/tags.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
+
/** Checks if tag is an "e" tag and has at least one value */
|
|
1
2
|
export function isETag(tag) {
|
|
2
3
|
return tag[0] === "e" && tag[1] !== undefined;
|
|
3
4
|
}
|
|
5
|
+
/** Checks if tag is an "p" tag and has at least one value */
|
|
4
6
|
export function isPTag(tag) {
|
|
5
7
|
return tag[0] === "p" && tag[1] !== undefined;
|
|
6
8
|
}
|
|
9
|
+
/** Checks if tag is an "r" tag and has at least one value */
|
|
7
10
|
export function isRTag(tag) {
|
|
8
11
|
return tag[0] === "r" && tag[1] !== undefined;
|
|
9
12
|
}
|
|
13
|
+
/** Checks if tag is an "d" tag and has at least one value */
|
|
10
14
|
export function isDTag(tag) {
|
|
11
15
|
return tag[0] === "d" && tag[1] !== undefined;
|
|
12
16
|
}
|
|
17
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
13
18
|
export function isATag(tag) {
|
|
14
19
|
return tag[0] === "a" && tag[1] !== undefined;
|
|
15
20
|
}
|
|
21
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
16
22
|
export function isTTag(tag) {
|
|
17
23
|
return tag[0] === "a" && tag[1] !== undefined;
|
|
18
24
|
}
|
package/dist/helpers/url.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ export declare const IMAGE_EXT: string[];
|
|
|
4
4
|
export declare const VIDEO_EXT: string[];
|
|
5
5
|
export declare const STREAM_EXT: string[];
|
|
6
6
|
export declare const AUDIO_EXT: string[];
|
|
7
|
-
|
|
7
|
+
/** Checks if a url is a image URL */
|
|
8
8
|
export declare function isImageURL(url: string | URL): boolean;
|
|
9
|
+
/** Checks if a url is a video URL */
|
|
9
10
|
export declare function isVideoURL(url: string | URL): boolean;
|
|
11
|
+
/** Checks if a url is a stream URL */
|
|
10
12
|
export declare function isStreamURL(url: string | URL): boolean;
|
|
13
|
+
/** Checks if a url is a audio URL */
|
|
11
14
|
export declare function isAudioURL(url: string | URL): boolean;
|
package/dist/helpers/url.js
CHANGED
|
@@ -4,24 +4,25 @@ export const IMAGE_EXT = [".svg", ".gif", ".png", ".jpg", ".jpeg", ".webp", ".av
|
|
|
4
4
|
export const VIDEO_EXT = [".mp4", ".mkv", ".webm", ".mov"];
|
|
5
5
|
export const STREAM_EXT = [".m3u8"];
|
|
6
6
|
export const AUDIO_EXT = [".mp3", ".wav", ".ogg", ".aac"];
|
|
7
|
-
|
|
8
|
-
return isImageURL(url) || isVideoURL(url) || isStreamURL(url);
|
|
9
|
-
}
|
|
7
|
+
/** Checks if a url is a image URL */
|
|
10
8
|
export function isImageURL(url) {
|
|
11
9
|
url = convertToUrl(url);
|
|
12
10
|
const filename = getURLFilename(url);
|
|
13
11
|
return !!filename && IMAGE_EXT.some((ext) => filename.endsWith(ext));
|
|
14
12
|
}
|
|
13
|
+
/** Checks if a url is a video URL */
|
|
15
14
|
export function isVideoURL(url) {
|
|
16
15
|
url = convertToUrl(url);
|
|
17
16
|
const filename = getURLFilename(url);
|
|
18
17
|
return !!filename && VIDEO_EXT.some((ext) => filename.endsWith(ext));
|
|
19
18
|
}
|
|
19
|
+
/** Checks if a url is a stream URL */
|
|
20
20
|
export function isStreamURL(url) {
|
|
21
21
|
url = convertToUrl(url);
|
|
22
22
|
const filename = getURLFilename(url);
|
|
23
23
|
return !!filename && STREAM_EXT.some((ext) => filename.endsWith(ext));
|
|
24
24
|
}
|
|
25
|
+
/** Checks if a url is a audio URL */
|
|
25
26
|
export function isAudioURL(url) {
|
|
26
27
|
url = convertToUrl(url);
|
|
27
28
|
const filename = getURLFilename(url);
|
package/dist/helpers/zap.d.ts
CHANGED
|
@@ -4,11 +4,28 @@ export declare const ZapFromSymbol: unique symbol;
|
|
|
4
4
|
export declare const ZapInvoiceSymbol: unique symbol;
|
|
5
5
|
export declare const ZapEventPointerSymbol: unique symbol;
|
|
6
6
|
export declare const ZapAddressPointerSymbol: unique symbol;
|
|
7
|
+
/** Returns the senders pubkey */
|
|
7
8
|
export declare function getZapSender(zap: NostrEvent): string;
|
|
9
|
+
/**
|
|
10
|
+
* Gets the receivers pubkey
|
|
11
|
+
* @throws
|
|
12
|
+
*/
|
|
8
13
|
export declare function getZapRecipient(zap: NostrEvent): string;
|
|
14
|
+
/** Returns the parsed bolt11 invoice */
|
|
9
15
|
export declare function getZapPayment(zap: NostrEvent): import("./bolt11.js").ParsedInvoice | undefined;
|
|
16
|
+
/** Gets the AddressPointer that was zapped */
|
|
10
17
|
export declare function getZapAddressPointer(zap: NostrEvent): import("nostr-tools/nip19").AddressPointer | null;
|
|
18
|
+
/** Gets the EventPointer that was zapped */
|
|
11
19
|
export declare function getZapEventPointer(zap: NostrEvent): import("nostr-tools/nip19").EventPointer | null;
|
|
20
|
+
/** Gets the preimage for the bolt11 invoice */
|
|
12
21
|
export declare function getZapPreimage(zap: NostrEvent): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the zap request event inside the zap receipt
|
|
24
|
+
* @throws
|
|
25
|
+
*/
|
|
13
26
|
export declare function getZapRequest(zap: NostrEvent): import("nostr-tools").Event;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if the zap is valid
|
|
29
|
+
* DOES NOT validate LNURL address
|
|
30
|
+
*/
|
|
14
31
|
export declare function isValidZap(zap?: NostrEvent): boolean;
|
package/dist/helpers/zap.js
CHANGED
|
@@ -9,36 +9,49 @@ export const ZapFromSymbol = Symbol.for("zap-from");
|
|
|
9
9
|
export const ZapInvoiceSymbol = Symbol.for("zap-bolt11");
|
|
10
10
|
export const ZapEventPointerSymbol = Symbol.for("zap-event-pointer");
|
|
11
11
|
export const ZapAddressPointerSymbol = Symbol.for("zap-address-pointer");
|
|
12
|
+
/** Returns the senders pubkey */
|
|
12
13
|
export function getZapSender(zap) {
|
|
13
14
|
return getTagValue(zap, "P") || getZapRequest(zap).pubkey;
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Gets the receivers pubkey
|
|
18
|
+
* @throws
|
|
19
|
+
*/
|
|
15
20
|
export function getZapRecipient(zap) {
|
|
16
21
|
const recipient = getTagValue(zap, "p");
|
|
17
22
|
if (!recipient)
|
|
18
23
|
throw new Error("Missing recipient");
|
|
19
24
|
return recipient;
|
|
20
25
|
}
|
|
26
|
+
/** Returns the parsed bolt11 invoice */
|
|
21
27
|
export function getZapPayment(zap) {
|
|
22
28
|
return getOrComputeCachedValue(zap, ZapInvoiceSymbol, () => {
|
|
23
29
|
const bolt11 = getTagValue(zap, "bolt11");
|
|
24
30
|
return bolt11 ? parseBolt11(bolt11) : undefined;
|
|
25
31
|
});
|
|
26
32
|
}
|
|
33
|
+
/** Gets the AddressPointer that was zapped */
|
|
27
34
|
export function getZapAddressPointer(zap) {
|
|
28
35
|
return getOrComputeCachedValue(zap, ZapAddressPointerSymbol, () => {
|
|
29
36
|
const a = zap.tags.find(isATag);
|
|
30
37
|
return a ? getAddressPointerFromTag(a) : null;
|
|
31
38
|
});
|
|
32
39
|
}
|
|
40
|
+
/** Gets the EventPointer that was zapped */
|
|
33
41
|
export function getZapEventPointer(zap) {
|
|
34
42
|
return getOrComputeCachedValue(zap, ZapEventPointerSymbol, () => {
|
|
35
43
|
const e = zap.tags.find(isETag);
|
|
36
44
|
return e ? getEventPointerFromTag(e) : null;
|
|
37
45
|
});
|
|
38
46
|
}
|
|
47
|
+
/** Gets the preimage for the bolt11 invoice */
|
|
39
48
|
export function getZapPreimage(zap) {
|
|
40
49
|
return getTagValue(zap, "preimage");
|
|
41
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the zap request event inside the zap receipt
|
|
53
|
+
* @throws
|
|
54
|
+
*/
|
|
42
55
|
export function getZapRequest(zap) {
|
|
43
56
|
return getOrComputeCachedValue(zap, ZapRequestSymbol, () => {
|
|
44
57
|
const description = getTagValue(zap, "description");
|
|
@@ -50,6 +63,10 @@ export function getZapRequest(zap) {
|
|
|
50
63
|
return JSON.parse(description);
|
|
51
64
|
});
|
|
52
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Checks if the zap is valid
|
|
68
|
+
* DOES NOT validate LNURL address
|
|
69
|
+
*/
|
|
53
70
|
export function isValidZap(zap) {
|
|
54
71
|
if (!zap)
|
|
55
72
|
return false;
|
package/dist/promise/deferred.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
2
|
import { map } from "rxjs/operators";
|
|
3
3
|
import { getInboxes, getOutboxes } from "../helpers/mailboxes.js";
|
|
4
|
+
/** A query that gets and parses the inbox and outbox relays for a pubkey */
|
|
4
5
|
export function MailboxesQuery(pubkey) {
|
|
5
6
|
return {
|
|
6
7
|
key: pubkey,
|
package/dist/queries/profile.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
2
|
import { filter, map } from "rxjs/operators";
|
|
3
3
|
import { getProfileContent, isValidProfile } from "../helpers/profile.js";
|
|
4
|
+
/** A query that gets and parses the kind 0 metadata for a pubkey */
|
|
4
5
|
export function ProfileQuery(pubkey) {
|
|
5
6
|
return {
|
|
6
7
|
key: pubkey,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { NostrEvent } from "nostr-tools";
|
|
2
2
|
import { Query } from "../query-store/index.js";
|
|
3
|
-
/**
|
|
3
|
+
/** A query that returns all reactions to an event (supports replaceable events) */
|
|
4
4
|
export declare function ReactionsQuery(event: NostrEvent): Query<NostrEvent[]>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
2
|
import { getEventUID, isReplaceable } from "../helpers/event.js";
|
|
3
|
-
/**
|
|
3
|
+
/** A query that returns all reactions to an event (supports replaceable events) */
|
|
4
4
|
export function ReactionsQuery(event) {
|
|
5
5
|
return {
|
|
6
6
|
key: getEventUID(event),
|
package/dist/queries/simple.js
CHANGED
package/dist/queries/thread.d.ts
CHANGED
|
@@ -21,3 +21,5 @@ export type ThreadQueryOptions = {
|
|
|
21
21
|
kinds?: number[];
|
|
22
22
|
};
|
|
23
23
|
export declare function ThreadQuery(root: string | AddressPointer | EventPointer, opts?: ThreadQueryOptions): Query<Thread>;
|
|
24
|
+
/** A query that gets all legacy and NIP-10 replies for an event */
|
|
25
|
+
export declare function RepliesQuery(event: NostrEvent, overrideKinds?: number[]): Query<NostrEvent[]>;
|
package/dist/queries/thread.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { kinds } from "nostr-tools";
|
|
2
|
+
import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
|
|
2
3
|
import { map } from "rxjs/operators";
|
|
3
|
-
import { getNip10References } from "../helpers/threading.js";
|
|
4
|
-
import { getCoordinateFromAddressPointer, isAddressPointer } from "../helpers/pointers.js";
|
|
5
|
-
import { getEventUID } from "../helpers/event.js";
|
|
4
|
+
import { getNip10References, interpretThreadTags } from "../helpers/threading.js";
|
|
5
|
+
import { getCoordinateFromAddressPointer, isAddressPointer, isEventPointer } from "../helpers/pointers.js";
|
|
6
|
+
import { getEventUID, getReplaceableUID, getTagValue, isEvent } from "../helpers/event.js";
|
|
6
7
|
const defaultOptions = {
|
|
7
8
|
kinds: [kinds.ShortTextNote],
|
|
8
9
|
};
|
|
@@ -64,3 +65,27 @@ export function ThreadQuery(root, opts) {
|
|
|
64
65
|
})),
|
|
65
66
|
};
|
|
66
67
|
}
|
|
68
|
+
/** A query that gets all legacy and NIP-10 replies for an event */
|
|
69
|
+
export function RepliesQuery(event, overrideKinds) {
|
|
70
|
+
return {
|
|
71
|
+
key: getEventUID(event),
|
|
72
|
+
run: (events) => {
|
|
73
|
+
const kinds = overrideKinds || event.kind === 1 ? [1, 1111] : [1111];
|
|
74
|
+
const filter = { kinds };
|
|
75
|
+
if (isEvent(parent) || isEventPointer(event))
|
|
76
|
+
filter["#e"] = [event.id];
|
|
77
|
+
const address = isParameterizedReplaceableKind(event.kind)
|
|
78
|
+
? getReplaceableUID(event.kind, event.pubkey, getTagValue(event, "d"))
|
|
79
|
+
: undefined;
|
|
80
|
+
if (address) {
|
|
81
|
+
filter["#a"] = [address];
|
|
82
|
+
}
|
|
83
|
+
return events.timeline(filter).pipe(map((events) => {
|
|
84
|
+
return events.filter((e) => {
|
|
85
|
+
const refs = interpretThreadTags(e);
|
|
86
|
+
return refs.reply?.e?.[1] === event.id || refs.reply?.a?.[1] === address;
|
|
87
|
+
});
|
|
88
|
+
}));
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
package/dist/queries/zaps.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AddressPointer, EventPointer } from "nostr-tools/nip19";
|
|
2
2
|
import { NostrEvent } from "nostr-tools";
|
|
3
3
|
import { Query } from "../query-store/index.js";
|
|
4
|
+
/** A query that gets all zap events for an event */
|
|
4
5
|
export declare function EventZapsQuery(id: string | EventPointer | AddressPointer): Query<NostrEvent[]>;
|
package/dist/queries/zaps.js
CHANGED
|
@@ -2,6 +2,7 @@ import { map } from "rxjs";
|
|
|
2
2
|
import { kinds } from "nostr-tools";
|
|
3
3
|
import { getCoordinateFromAddressPointer, isAddressPointer } from "../helpers/pointers.js";
|
|
4
4
|
import { isValidZap } from "../helpers/zap.js";
|
|
5
|
+
/** A query that gets all zap events for an event */
|
|
5
6
|
export function EventZapsQuery(id) {
|
|
6
7
|
return {
|
|
7
8
|
key: JSON.stringify(id),
|
|
@@ -5,8 +5,15 @@ import { LRU } from "../helpers/lru.js";
|
|
|
5
5
|
import * as Queries from "../queries/index.js";
|
|
6
6
|
import { AddressPointer, EventPointer } from "nostr-tools/nip19";
|
|
7
7
|
export type Query<T extends unknown> = {
|
|
8
|
+
/**
|
|
9
|
+
* A unique key for this query. this is used to detect duplicate queries
|
|
10
|
+
*/
|
|
8
11
|
key: string;
|
|
12
|
+
/** The args array this query was created with. This is mostly for debugging */
|
|
9
13
|
args?: Array<any>;
|
|
14
|
+
/**
|
|
15
|
+
* The meat of the query, this should return an Observables that subscribes to the eventStore in some way
|
|
16
|
+
*/
|
|
10
17
|
run: (events: EventStore, store: QueryStore) => Observable<T>;
|
|
11
18
|
};
|
|
12
19
|
export type QueryConstructor<T extends unknown, Args extends Array<any>> = (...args: Args) => Query<T>;
|
|
@@ -17,33 +24,34 @@ export declare class QueryStore {
|
|
|
17
24
|
queries: LRU<Query<any>>;
|
|
18
25
|
observables: WeakMap<Query<any>, Observable<any> | BehaviorSubject<any>>;
|
|
19
26
|
/** Creates a cached query */
|
|
20
|
-
|
|
27
|
+
createQuery<T extends unknown, Args extends Array<any>>(queryConstructor: (...args: Args) => {
|
|
21
28
|
key: string;
|
|
22
29
|
run: (events: EventStore, store: QueryStore) => Observable<T>;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
30
|
+
}, ...args: Args): Observable<T>;
|
|
31
|
+
/** Creates a SingleEventQuery */
|
|
25
32
|
event(id: string): Observable<import("nostr-tools").Event | undefined>;
|
|
26
|
-
/**
|
|
33
|
+
/** Creates a MultipleEventsQuery */
|
|
27
34
|
events(ids: string[]): Observable<Map<string, import("nostr-tools").Event>>;
|
|
28
|
-
/**
|
|
35
|
+
/** Creates a ReplaceableQuery */
|
|
29
36
|
replaceable(kind: number, pubkey: string, d?: string): Observable<import("nostr-tools").Event | undefined>;
|
|
30
|
-
/**
|
|
37
|
+
/** Creates a ReplaceableSetQuery */
|
|
31
38
|
replaceableSet(pointers: {
|
|
32
39
|
kind: number;
|
|
33
40
|
pubkey: string;
|
|
34
41
|
identifier?: string;
|
|
35
42
|
}[]): Observable<Map<string, import("nostr-tools").Event>>;
|
|
36
|
-
/**
|
|
43
|
+
/** Creates a TimelineQuery */
|
|
37
44
|
timeline(filters: Filter | Filter[], keepOldVersions?: boolean): Observable<import("nostr-tools").Event[]>;
|
|
38
|
-
/**
|
|
45
|
+
/** Creates a ProfileQuery */
|
|
39
46
|
profile(pubkey: string): Observable<import("../helpers/profile.js").ProfileContent | undefined>;
|
|
40
|
-
/**
|
|
47
|
+
/** Creates a ReactionsQuery */
|
|
41
48
|
reactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
|
|
42
|
-
/**
|
|
49
|
+
/** Creates a MailboxesQuery */
|
|
43
50
|
mailboxes(pubkey: string): Observable<{
|
|
44
51
|
inboxes: string[];
|
|
45
52
|
outboxes: string[];
|
|
46
53
|
} | undefined>;
|
|
54
|
+
/** Creates a ThreadQuery */
|
|
47
55
|
thread(root: string | EventPointer | AddressPointer): Observable<Queries.Thread>;
|
|
48
56
|
}
|
|
49
57
|
export { Queries };
|
|
@@ -10,58 +10,57 @@ export class QueryStore {
|
|
|
10
10
|
queries = new LRU();
|
|
11
11
|
observables = new WeakMap();
|
|
12
12
|
/** Creates a cached query */
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return this.observables.get(query);
|
|
29
|
-
};
|
|
13
|
+
createQuery(queryConstructor, ...args) {
|
|
14
|
+
const tempQuery = queryConstructor(...args);
|
|
15
|
+
const key = `${queryConstructor.name}|${tempQuery.key}`;
|
|
16
|
+
let query = this.queries.get(key);
|
|
17
|
+
if (!query) {
|
|
18
|
+
query = tempQuery;
|
|
19
|
+
this.queries.set(key, tempQuery);
|
|
20
|
+
}
|
|
21
|
+
if (!this.observables.has(query)) {
|
|
22
|
+
query.args = args;
|
|
23
|
+
const observable = query.run(this.store, this).pipe(shareLatestValue());
|
|
24
|
+
this.observables.set(query, observable);
|
|
25
|
+
return observable;
|
|
26
|
+
}
|
|
27
|
+
return this.observables.get(query);
|
|
30
28
|
}
|
|
31
|
-
/**
|
|
29
|
+
/** Creates a SingleEventQuery */
|
|
32
30
|
event(id) {
|
|
33
|
-
return this.
|
|
31
|
+
return this.createQuery(Queries.SingleEventQuery, id);
|
|
34
32
|
}
|
|
35
|
-
/**
|
|
33
|
+
/** Creates a MultipleEventsQuery */
|
|
36
34
|
events(ids) {
|
|
37
|
-
return this.
|
|
35
|
+
return this.createQuery(Queries.MultipleEventsQuery, ids);
|
|
38
36
|
}
|
|
39
|
-
/**
|
|
37
|
+
/** Creates a ReplaceableQuery */
|
|
40
38
|
replaceable(kind, pubkey, d) {
|
|
41
|
-
return this.
|
|
39
|
+
return this.createQuery(Queries.ReplaceableQuery, kind, pubkey, d);
|
|
42
40
|
}
|
|
43
|
-
/**
|
|
41
|
+
/** Creates a ReplaceableSetQuery */
|
|
44
42
|
replaceableSet(pointers) {
|
|
45
|
-
return this.
|
|
43
|
+
return this.createQuery(Queries.ReplaceableSetQuery, pointers);
|
|
46
44
|
}
|
|
47
|
-
/**
|
|
45
|
+
/** Creates a TimelineQuery */
|
|
48
46
|
timeline(filters, keepOldVersions) {
|
|
49
|
-
return this.
|
|
47
|
+
return this.createQuery(Queries.TimelineQuery, filters, keepOldVersions);
|
|
50
48
|
}
|
|
51
|
-
/**
|
|
49
|
+
/** Creates a ProfileQuery */
|
|
52
50
|
profile(pubkey) {
|
|
53
|
-
return this.
|
|
51
|
+
return this.createQuery(Queries.ProfileQuery, pubkey);
|
|
54
52
|
}
|
|
55
|
-
/**
|
|
53
|
+
/** Creates a ReactionsQuery */
|
|
56
54
|
reactions(event) {
|
|
57
|
-
return this.
|
|
55
|
+
return this.createQuery(Queries.ReactionsQuery, event);
|
|
58
56
|
}
|
|
59
|
-
/**
|
|
57
|
+
/** Creates a MailboxesQuery */
|
|
60
58
|
mailboxes(pubkey) {
|
|
61
|
-
return this.
|
|
59
|
+
return this.createQuery(Queries.MailboxesQuery, pubkey);
|
|
62
60
|
}
|
|
61
|
+
/** Creates a ThreadQuery */
|
|
63
62
|
thread(root) {
|
|
64
|
-
return this.
|
|
63
|
+
return this.createQuery(Queries.ThreadQuery, root);
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
export { Queries };
|