applesauce-core 0.0.0-next-20250123214405 → 0.0.0-next-20250123215242
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/common.d.ts +1 -0
- package/dist/event-store/common.js +2 -0
- package/dist/event-store/database.d.ts +64 -0
- package/dist/event-store/database.js +311 -0
- package/dist/event-store/event-store.d.ts +49 -0
- package/dist/event-store/event-store.js +389 -0
- package/dist/event-store/index.d.ts +2 -0
- package/dist/event-store/index.js +2 -0
- package/dist/helpers/bolt11.d.ts +9 -0
- package/dist/helpers/bolt11.js +15 -0
- package/dist/helpers/cache.d.ts +5 -0
- package/dist/helpers/cache.js +17 -0
- package/dist/helpers/comment.d.ts +47 -0
- package/dist/helpers/comment.js +116 -0
- package/dist/helpers/content.d.ts +3 -0
- package/dist/helpers/content.js +8 -0
- package/dist/helpers/delete.d.ts +3 -0
- package/dist/helpers/delete.js +7 -0
- package/dist/helpers/emoji.d.ts +11 -0
- package/dist/helpers/emoji.js +16 -0
- package/dist/helpers/event.d.ts +48 -0
- package/dist/helpers/event.js +105 -0
- package/dist/helpers/external-id.d.ts +29 -0
- package/dist/helpers/external-id.js +20 -0
- package/dist/helpers/file-metadata.d.ts +53 -0
- package/dist/helpers/file-metadata.js +90 -0
- package/dist/helpers/file-metadata.test.d.ts +1 -0
- package/dist/helpers/file-metadata.test.js +103 -0
- package/dist/helpers/filter.d.ts +10 -0
- package/dist/helpers/filter.js +46 -0
- package/dist/helpers/groups.d.ts +14 -0
- package/dist/helpers/groups.js +16 -0
- package/dist/helpers/hashtag.d.ts +2 -0
- package/dist/helpers/hashtag.js +7 -0
- package/dist/helpers/hidden-tags.d.ts +48 -0
- package/dist/helpers/hidden-tags.js +108 -0
- package/dist/helpers/hidden-tags.test.d.ts +1 -0
- package/dist/helpers/hidden-tags.test.js +28 -0
- package/dist/helpers/index.d.ts +28 -0
- package/dist/helpers/index.js +28 -0
- package/dist/helpers/json.d.ts +2 -0
- package/dist/helpers/json.js +9 -0
- package/dist/helpers/lnurl.d.ts +4 -0
- package/dist/helpers/lnurl.js +40 -0
- package/dist/helpers/lru.d.ts +32 -0
- package/dist/helpers/lru.js +148 -0
- package/dist/helpers/mailboxes.d.ts +11 -0
- package/dist/helpers/mailboxes.js +36 -0
- package/dist/helpers/mailboxes.test.d.ts +1 -0
- package/dist/helpers/mailboxes.test.js +81 -0
- package/dist/helpers/picture-post.d.ts +4 -0
- package/dist/helpers/picture-post.js +6 -0
- package/dist/helpers/pointers.d.ts +55 -0
- package/dist/helpers/pointers.js +205 -0
- package/dist/helpers/profile.d.ts +20 -0
- package/dist/helpers/profile.js +31 -0
- package/dist/helpers/relays.d.ts +12 -0
- package/dist/helpers/relays.js +31 -0
- package/dist/helpers/share.d.ts +4 -0
- package/dist/helpers/share.js +12 -0
- package/dist/helpers/string.d.ts +10 -0
- package/dist/helpers/string.js +15 -0
- package/dist/helpers/tags.d.ts +25 -0
- package/dist/helpers/tags.js +42 -0
- package/dist/helpers/tags.test.d.ts +1 -0
- package/dist/helpers/tags.test.js +16 -0
- package/dist/helpers/threading.d.ts +55 -0
- package/dist/helpers/threading.js +94 -0
- package/dist/helpers/threading.test.d.ts +1 -0
- package/dist/helpers/threading.test.js +41 -0
- package/dist/helpers/time.d.ts +2 -0
- package/dist/helpers/time.js +4 -0
- package/dist/helpers/url.d.ts +14 -0
- package/dist/helpers/url.js +30 -0
- package/dist/helpers/zap.d.ts +39 -0
- package/dist/helpers/zap.js +95 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +2 -0
- package/dist/observable/get-value.d.ts +3 -0
- package/dist/observable/get-value.js +14 -0
- package/dist/observable/index.d.ts +2 -0
- package/dist/observable/index.js +2 -0
- package/dist/observable/share-latest-value.d.ts +8 -0
- package/dist/observable/share-latest-value.js +21 -0
- package/dist/promise/deferred.d.ts +6 -0
- package/dist/promise/deferred.js +15 -0
- package/dist/promise/index.d.ts +1 -0
- package/dist/promise/index.js +1 -0
- package/dist/queries/comments.d.ts +4 -0
- package/dist/queries/comments.js +14 -0
- package/dist/queries/index.d.ts +7 -0
- package/dist/queries/index.js +7 -0
- package/dist/queries/mailboxes.d.ts +6 -0
- package/dist/queries/mailboxes.js +13 -0
- package/dist/queries/profile.d.ts +4 -0
- package/dist/queries/profile.js +12 -0
- package/dist/queries/reactions.d.ts +4 -0
- package/dist/queries/reactions.js +19 -0
- package/dist/queries/simple.d.ts +16 -0
- package/dist/queries/simple.js +38 -0
- package/dist/queries/thread.d.ts +25 -0
- package/dist/queries/thread.js +92 -0
- package/dist/queries/zaps.d.ts +5 -0
- package/dist/queries/zaps.js +21 -0
- package/dist/query-store/index.d.ts +57 -0
- package/dist/query-store/index.js +68 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const INDEXABLE_TAGS: Set<string>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Filter, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { Subject } from "rxjs";
|
|
3
|
+
import { LRU } from "../helpers/lru.js";
|
|
4
|
+
/**
|
|
5
|
+
* An in-memory database for nostr events
|
|
6
|
+
* NOTE: does not handle replaceable events
|
|
7
|
+
*/
|
|
8
|
+
export declare class Database {
|
|
9
|
+
protected log: import("debug").Debugger;
|
|
10
|
+
/** Indexes */
|
|
11
|
+
protected kinds: Map<number, Set<import("nostr-tools").Event>>;
|
|
12
|
+
protected authors: Map<string, Set<import("nostr-tools").Event>>;
|
|
13
|
+
protected tags: LRU<Set<import("nostr-tools").Event>>;
|
|
14
|
+
protected created_at: NostrEvent[];
|
|
15
|
+
/** LRU cache of last events touched */
|
|
16
|
+
events: LRU<import("nostr-tools").Event>;
|
|
17
|
+
protected replaceable: Map<string, import("nostr-tools").Event[]>;
|
|
18
|
+
/** A stream of events inserted into the database */
|
|
19
|
+
inserted: Subject<import("nostr-tools").Event>;
|
|
20
|
+
/** A stream of events that have been updated */
|
|
21
|
+
updated: Subject<import("nostr-tools").Event>;
|
|
22
|
+
/** A stream of events removed of the database */
|
|
23
|
+
deleted: Subject<import("nostr-tools").Event>;
|
|
24
|
+
get size(): number;
|
|
25
|
+
protected claims: WeakMap<import("nostr-tools").Event, any>;
|
|
26
|
+
/** Index helper methods */
|
|
27
|
+
protected getKindIndex(kind: number): Set<import("nostr-tools").Event>;
|
|
28
|
+
protected getAuthorsIndex(author: string): Set<import("nostr-tools").Event>;
|
|
29
|
+
protected getTagIndex(tagAndValue: string): Set<import("nostr-tools").Event>;
|
|
30
|
+
/** Moves an event to the top of the LRU cache */
|
|
31
|
+
touch(event: NostrEvent): void;
|
|
32
|
+
/** Checks if the database contains an event without touching it */
|
|
33
|
+
hasEvent(id: string): boolean;
|
|
34
|
+
/** Gets a single event based on id */
|
|
35
|
+
getEvent(id: string): NostrEvent | undefined;
|
|
36
|
+
/** Checks if the database contains a replaceable event without touching it */
|
|
37
|
+
hasReplaceable(kind: number, pubkey: string, d?: string): boolean;
|
|
38
|
+
/** Gets an array of replaceable events */
|
|
39
|
+
getReplaceable(kind: number, pubkey: string, d?: string): NostrEvent[] | undefined;
|
|
40
|
+
/** Inserts an event into the database and notifies all subscriptions */
|
|
41
|
+
addEvent(event: NostrEvent): NostrEvent;
|
|
42
|
+
/** Inserts and event into the database and notifies all subscriptions that the event has updated */
|
|
43
|
+
updateEvent(event: NostrEvent): NostrEvent;
|
|
44
|
+
/** Deletes an event from the database and notifies all subscriptions */
|
|
45
|
+
deleteEvent(eventOrId: string | NostrEvent): boolean;
|
|
46
|
+
/** Sets the claim on the event and touches it */
|
|
47
|
+
claimEvent(event: NostrEvent, claim: any): void;
|
|
48
|
+
/** Checks if an event is claimed by anything */
|
|
49
|
+
isClaimed(event: NostrEvent): boolean;
|
|
50
|
+
/** Removes a claim from an event */
|
|
51
|
+
removeClaim(event: NostrEvent, claim: any): void;
|
|
52
|
+
/** Removes all claims on an event */
|
|
53
|
+
clearClaim(event: NostrEvent): void;
|
|
54
|
+
iterateAuthors(authors: Iterable<string>): Generator<NostrEvent>;
|
|
55
|
+
iterateTag(tag: string, values: Iterable<string>): Generator<NostrEvent>;
|
|
56
|
+
iterateKinds(kinds: Iterable<number>): Generator<NostrEvent>;
|
|
57
|
+
iterateTime(since: number | undefined, until: number | undefined): Generator<NostrEvent>;
|
|
58
|
+
iterateIds(ids: Iterable<string>): Generator<NostrEvent>;
|
|
59
|
+
/** Returns all events that match the filter */
|
|
60
|
+
getEventsForFilter(filter: Filter): Set<NostrEvent>;
|
|
61
|
+
getForFilters(filters: Filter[]): Set<NostrEvent>;
|
|
62
|
+
/** Remove the oldest events that are not claimed */
|
|
63
|
+
prune(limit?: number): number;
|
|
64
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { binarySearch, insertEventIntoDescendingList } from "nostr-tools/utils";
|
|
2
|
+
import { Subject } from "rxjs";
|
|
3
|
+
import { FromCacheSymbol, getEventUID, getIndexableTags, getReplaceableUID, isReplaceable } from "../helpers/event.js";
|
|
4
|
+
import { INDEXABLE_TAGS } from "./common.js";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
import { LRU } from "../helpers/lru.js";
|
|
7
|
+
/**
|
|
8
|
+
* An in-memory database for nostr events
|
|
9
|
+
* NOTE: does not handle replaceable events
|
|
10
|
+
*/
|
|
11
|
+
export class Database {
|
|
12
|
+
log = logger.extend("Database");
|
|
13
|
+
/** Indexes */
|
|
14
|
+
kinds = new Map();
|
|
15
|
+
authors = new Map();
|
|
16
|
+
tags = new LRU();
|
|
17
|
+
created_at = [];
|
|
18
|
+
/** LRU cache of last events touched */
|
|
19
|
+
events = new LRU();
|
|
20
|
+
replaceable = new Map();
|
|
21
|
+
/** A stream of events inserted into the database */
|
|
22
|
+
inserted = new Subject();
|
|
23
|
+
/** A stream of events that have been updated */
|
|
24
|
+
updated = new Subject();
|
|
25
|
+
/** A stream of events removed of the database */
|
|
26
|
+
deleted = new Subject();
|
|
27
|
+
get size() {
|
|
28
|
+
return this.events.size;
|
|
29
|
+
}
|
|
30
|
+
claims = new WeakMap();
|
|
31
|
+
/** Index helper methods */
|
|
32
|
+
getKindIndex(kind) {
|
|
33
|
+
if (!this.kinds.has(kind))
|
|
34
|
+
this.kinds.set(kind, new Set());
|
|
35
|
+
return this.kinds.get(kind);
|
|
36
|
+
}
|
|
37
|
+
getAuthorsIndex(author) {
|
|
38
|
+
if (!this.authors.has(author))
|
|
39
|
+
this.authors.set(author, new Set());
|
|
40
|
+
return this.authors.get(author);
|
|
41
|
+
}
|
|
42
|
+
getTagIndex(tagAndValue) {
|
|
43
|
+
if (!this.tags.has(tagAndValue)) {
|
|
44
|
+
// build new tag index from existing events
|
|
45
|
+
const events = new Set();
|
|
46
|
+
const ts = Date.now();
|
|
47
|
+
for (const event of this.events.values()) {
|
|
48
|
+
if (getIndexableTags(event).has(tagAndValue)) {
|
|
49
|
+
events.add(event);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const took = Date.now() - ts;
|
|
53
|
+
if (took > 100)
|
|
54
|
+
this.log(`Built index ${tagAndValue} took ${took}ms`);
|
|
55
|
+
this.tags.set(tagAndValue, events);
|
|
56
|
+
}
|
|
57
|
+
return this.tags.get(tagAndValue);
|
|
58
|
+
}
|
|
59
|
+
/** Moves an event to the top of the LRU cache */
|
|
60
|
+
touch(event) {
|
|
61
|
+
this.events.set(event.id, event);
|
|
62
|
+
}
|
|
63
|
+
/** Checks if the database contains an event without touching it */
|
|
64
|
+
hasEvent(id) {
|
|
65
|
+
return this.events.has(id);
|
|
66
|
+
}
|
|
67
|
+
/** Gets a single event based on id */
|
|
68
|
+
getEvent(id) {
|
|
69
|
+
return this.events.get(id);
|
|
70
|
+
}
|
|
71
|
+
/** Checks if the database contains a replaceable event without touching it */
|
|
72
|
+
hasReplaceable(kind, pubkey, d) {
|
|
73
|
+
const events = this.replaceable.get(getReplaceableUID(kind, pubkey, d));
|
|
74
|
+
return !!events && events.length > 0;
|
|
75
|
+
}
|
|
76
|
+
/** Gets an array of replaceable events */
|
|
77
|
+
getReplaceable(kind, pubkey, d) {
|
|
78
|
+
return this.replaceable.get(getReplaceableUID(kind, pubkey, d));
|
|
79
|
+
}
|
|
80
|
+
/** Inserts an event into the database and notifies all subscriptions */
|
|
81
|
+
addEvent(event) {
|
|
82
|
+
const id = event.id;
|
|
83
|
+
const current = this.events.get(id);
|
|
84
|
+
if (current) {
|
|
85
|
+
// if this is a duplicate event, transfer some import symbols
|
|
86
|
+
if (event[FromCacheSymbol])
|
|
87
|
+
current[FromCacheSymbol] = event[FromCacheSymbol];
|
|
88
|
+
return current;
|
|
89
|
+
}
|
|
90
|
+
this.events.set(id, event);
|
|
91
|
+
this.getKindIndex(event.kind).add(event);
|
|
92
|
+
this.getAuthorsIndex(event.pubkey).add(event);
|
|
93
|
+
for (const tag of getIndexableTags(event)) {
|
|
94
|
+
if (this.tags.has(tag)) {
|
|
95
|
+
this.getTagIndex(tag).add(event);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// insert into time index
|
|
99
|
+
insertEventIntoDescendingList(this.created_at, event);
|
|
100
|
+
// insert into replaceable index
|
|
101
|
+
if (isReplaceable(event.kind)) {
|
|
102
|
+
const uid = getEventUID(event);
|
|
103
|
+
let array = this.replaceable.get(uid);
|
|
104
|
+
if (!this.replaceable.has(uid)) {
|
|
105
|
+
array = [];
|
|
106
|
+
this.replaceable.set(uid, array);
|
|
107
|
+
}
|
|
108
|
+
insertEventIntoDescendingList(array, event);
|
|
109
|
+
}
|
|
110
|
+
this.inserted.next(event);
|
|
111
|
+
return event;
|
|
112
|
+
}
|
|
113
|
+
/** Inserts and event into the database and notifies all subscriptions that the event has updated */
|
|
114
|
+
updateEvent(event) {
|
|
115
|
+
const inserted = this.addEvent(event);
|
|
116
|
+
this.updated.next(inserted);
|
|
117
|
+
return inserted;
|
|
118
|
+
}
|
|
119
|
+
/** Deletes an event from the database and notifies all subscriptions */
|
|
120
|
+
deleteEvent(eventOrId) {
|
|
121
|
+
let event = typeof eventOrId === "string" ? this.events.get(eventOrId) : eventOrId;
|
|
122
|
+
if (!event)
|
|
123
|
+
throw new Error("Missing event");
|
|
124
|
+
const id = event.id;
|
|
125
|
+
// only remove events that are known
|
|
126
|
+
if (!this.events.has(id))
|
|
127
|
+
return false;
|
|
128
|
+
this.getAuthorsIndex(event.pubkey).delete(event);
|
|
129
|
+
this.getKindIndex(event.kind).delete(event);
|
|
130
|
+
for (const tag of getIndexableTags(event)) {
|
|
131
|
+
if (this.tags.has(tag)) {
|
|
132
|
+
this.getTagIndex(tag).delete(event);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// remove from created_at index
|
|
136
|
+
const i = this.created_at.indexOf(event);
|
|
137
|
+
this.created_at.splice(i, 1);
|
|
138
|
+
this.events.delete(id);
|
|
139
|
+
// remove from replaceable index
|
|
140
|
+
if (isReplaceable(event.kind)) {
|
|
141
|
+
const uid = getEventUID(event);
|
|
142
|
+
const array = this.replaceable.get(uid);
|
|
143
|
+
if (array && array.includes(event)) {
|
|
144
|
+
const idx = array.indexOf(event);
|
|
145
|
+
array.splice(idx, 1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.deleted.next(event);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
/** Sets the claim on the event and touches it */
|
|
152
|
+
claimEvent(event, claim) {
|
|
153
|
+
if (!this.claims.has(event)) {
|
|
154
|
+
this.claims.set(event, claim);
|
|
155
|
+
}
|
|
156
|
+
// always touch event
|
|
157
|
+
this.touch(event);
|
|
158
|
+
}
|
|
159
|
+
/** Checks if an event is claimed by anything */
|
|
160
|
+
isClaimed(event) {
|
|
161
|
+
return this.claims.has(event);
|
|
162
|
+
}
|
|
163
|
+
/** Removes a claim from an event */
|
|
164
|
+
removeClaim(event, claim) {
|
|
165
|
+
const current = this.claims.get(event);
|
|
166
|
+
if (current === claim)
|
|
167
|
+
this.claims.delete(event);
|
|
168
|
+
}
|
|
169
|
+
/** Removes all claims on an event */
|
|
170
|
+
clearClaim(event) {
|
|
171
|
+
this.claims.delete(event);
|
|
172
|
+
}
|
|
173
|
+
*iterateAuthors(authors) {
|
|
174
|
+
for (const author of authors) {
|
|
175
|
+
const events = this.authors.get(author);
|
|
176
|
+
if (events) {
|
|
177
|
+
for (const event of events)
|
|
178
|
+
yield event;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
*iterateTag(tag, values) {
|
|
183
|
+
for (const value of values) {
|
|
184
|
+
const events = this.getTagIndex(tag + ":" + value);
|
|
185
|
+
if (events) {
|
|
186
|
+
for (const event of events)
|
|
187
|
+
yield event;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
*iterateKinds(kinds) {
|
|
192
|
+
for (const kind of kinds) {
|
|
193
|
+
const events = this.kinds.get(kind);
|
|
194
|
+
if (events) {
|
|
195
|
+
for (const event of events)
|
|
196
|
+
yield event;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
*iterateTime(since, until) {
|
|
201
|
+
let untilIndex = 0;
|
|
202
|
+
let sinceIndex = this.created_at.length - 1;
|
|
203
|
+
let start = until
|
|
204
|
+
? binarySearch(this.created_at, (mid) => {
|
|
205
|
+
return mid.created_at - until;
|
|
206
|
+
})
|
|
207
|
+
: undefined;
|
|
208
|
+
if (start)
|
|
209
|
+
untilIndex = start[0];
|
|
210
|
+
const end = since
|
|
211
|
+
? binarySearch(this.created_at, (mid) => {
|
|
212
|
+
return mid.created_at - since;
|
|
213
|
+
})
|
|
214
|
+
: undefined;
|
|
215
|
+
if (end)
|
|
216
|
+
sinceIndex = end[0];
|
|
217
|
+
for (let i = untilIndex; i < sinceIndex; i++) {
|
|
218
|
+
yield this.created_at[i];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
*iterateIds(ids) {
|
|
222
|
+
for (const id of ids) {
|
|
223
|
+
if (this.events.has(id))
|
|
224
|
+
yield this.events.get(id);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** Returns all events that match the filter */
|
|
228
|
+
getEventsForFilter(filter) {
|
|
229
|
+
// search is not supported, return an empty set
|
|
230
|
+
if (filter.search)
|
|
231
|
+
return new Set();
|
|
232
|
+
let first = true;
|
|
233
|
+
let events = new Set();
|
|
234
|
+
const and = (iterable) => {
|
|
235
|
+
const set = iterable instanceof Set ? iterable : new Set(iterable);
|
|
236
|
+
if (first) {
|
|
237
|
+
events = set;
|
|
238
|
+
first = false;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
for (const event of events) {
|
|
242
|
+
if (!set.has(event))
|
|
243
|
+
events.delete(event);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return events;
|
|
247
|
+
};
|
|
248
|
+
if (filter.ids)
|
|
249
|
+
and(this.iterateIds(filter.ids));
|
|
250
|
+
let time = null;
|
|
251
|
+
// query for time first if since is set
|
|
252
|
+
if (filter.since !== undefined) {
|
|
253
|
+
time = Array.from(this.iterateTime(filter.since, filter.until));
|
|
254
|
+
and(time);
|
|
255
|
+
}
|
|
256
|
+
for (const t of INDEXABLE_TAGS) {
|
|
257
|
+
const key = `#${t}`;
|
|
258
|
+
const values = filter[key];
|
|
259
|
+
if (values?.length)
|
|
260
|
+
and(this.iterateTag(t, values));
|
|
261
|
+
}
|
|
262
|
+
if (filter.authors)
|
|
263
|
+
and(this.iterateAuthors(filter.authors));
|
|
264
|
+
if (filter.kinds)
|
|
265
|
+
and(this.iterateKinds(filter.kinds));
|
|
266
|
+
// query for time last if only until is set
|
|
267
|
+
if (filter.since === undefined && filter.until !== undefined) {
|
|
268
|
+
time = Array.from(this.iterateTime(filter.since, filter.until));
|
|
269
|
+
and(time);
|
|
270
|
+
}
|
|
271
|
+
// if the filter queried on time and has a limit. truncate the events now
|
|
272
|
+
if (filter.limit && time) {
|
|
273
|
+
const limited = new Set();
|
|
274
|
+
for (const event of time) {
|
|
275
|
+
if (limited.size >= filter.limit)
|
|
276
|
+
break;
|
|
277
|
+
if (events.has(event))
|
|
278
|
+
limited.add(event);
|
|
279
|
+
}
|
|
280
|
+
return limited;
|
|
281
|
+
}
|
|
282
|
+
return events;
|
|
283
|
+
}
|
|
284
|
+
getForFilters(filters) {
|
|
285
|
+
if (filters.length === 0)
|
|
286
|
+
throw new Error("No Filters");
|
|
287
|
+
let events = new Set();
|
|
288
|
+
for (const filter of filters) {
|
|
289
|
+
const filtered = this.getEventsForFilter(filter);
|
|
290
|
+
for (const event of filtered)
|
|
291
|
+
events.add(event);
|
|
292
|
+
}
|
|
293
|
+
return events;
|
|
294
|
+
}
|
|
295
|
+
/** Remove the oldest events that are not claimed */
|
|
296
|
+
prune(limit = 1000) {
|
|
297
|
+
let removed = 0;
|
|
298
|
+
let cursor = this.events.first;
|
|
299
|
+
while (cursor) {
|
|
300
|
+
const event = cursor.value;
|
|
301
|
+
if (!this.isClaimed(event)) {
|
|
302
|
+
this.deleteEvent(event);
|
|
303
|
+
removed++;
|
|
304
|
+
if (removed >= limit)
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
cursor = cursor.next;
|
|
308
|
+
}
|
|
309
|
+
return removed;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Filter, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { Database } from "./database.js";
|
|
4
|
+
export declare class EventStore {
|
|
5
|
+
database: Database;
|
|
6
|
+
/** Enable this to keep old versions of replaceable events */
|
|
7
|
+
keepOldVersions: boolean;
|
|
8
|
+
constructor();
|
|
9
|
+
/** Adds an event to the database and update subscriptions */
|
|
10
|
+
add(event: NostrEvent, fromRelay?: string): NostrEvent;
|
|
11
|
+
/** Removes an event from the database and updates subscriptions */
|
|
12
|
+
remove(event: string | NostrEvent): boolean;
|
|
13
|
+
protected deletedIds: Set<string>;
|
|
14
|
+
protected deletedCoords: Map<string, number>;
|
|
15
|
+
protected handleDeleteEvent(deleteEvent: NostrEvent): void;
|
|
16
|
+
protected checkDeleted(event: NostrEvent): boolean;
|
|
17
|
+
/** Removes any event that is not being used by a subscription */
|
|
18
|
+
prune(max?: number): number;
|
|
19
|
+
/** Add an event to the store and notifies all subscribes it has updated */
|
|
20
|
+
update(event: NostrEvent): NostrEvent;
|
|
21
|
+
getAll(filters: Filter[]): Set<NostrEvent>;
|
|
22
|
+
hasEvent(uid: string): boolean;
|
|
23
|
+
getEvent(uid: string): NostrEvent | undefined;
|
|
24
|
+
hasReplaceable(kind: number, pubkey: string, d?: string): boolean;
|
|
25
|
+
/** Gets the latest version of a replaceable event */
|
|
26
|
+
getReplaceable(kind: number, pubkey: string, d?: string): NostrEvent | undefined;
|
|
27
|
+
/** Returns all versions of a replaceable event */
|
|
28
|
+
getReplaceableHistory(kind: number, pubkey: string, d?: string): NostrEvent[] | undefined;
|
|
29
|
+
/** Creates an observable that updates a single event */
|
|
30
|
+
event(id: string): Observable<NostrEvent | undefined>;
|
|
31
|
+
/** Creates an observable that subscribes to multiple events */
|
|
32
|
+
events(ids: string[]): Observable<Record<string, NostrEvent>>;
|
|
33
|
+
/** Creates an observable with the latest version of a replaceable event */
|
|
34
|
+
replaceable(kind: number, pubkey: string, d?: string): Observable<NostrEvent | undefined>;
|
|
35
|
+
/** Creates an observable with the latest versions of replaceable events */
|
|
36
|
+
replaceableSet(pointers: {
|
|
37
|
+
kind: number;
|
|
38
|
+
pubkey: string;
|
|
39
|
+
identifier?: string;
|
|
40
|
+
}[]): Observable<Record<string, NostrEvent>>;
|
|
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>;
|
|
47
|
+
/** Creates an observable that updates with an array of sorted events */
|
|
48
|
+
timeline(filters: Filter | Filter[], keepOldVersions?: boolean): Observable<NostrEvent[]>;
|
|
49
|
+
}
|