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.
Files changed (109) hide show
  1. package/dist/event-store/common.d.ts +1 -0
  2. package/dist/event-store/common.js +2 -0
  3. package/dist/event-store/database.d.ts +64 -0
  4. package/dist/event-store/database.js +311 -0
  5. package/dist/event-store/event-store.d.ts +49 -0
  6. package/dist/event-store/event-store.js +389 -0
  7. package/dist/event-store/index.d.ts +2 -0
  8. package/dist/event-store/index.js +2 -0
  9. package/dist/helpers/bolt11.d.ts +9 -0
  10. package/dist/helpers/bolt11.js +15 -0
  11. package/dist/helpers/cache.d.ts +5 -0
  12. package/dist/helpers/cache.js +17 -0
  13. package/dist/helpers/comment.d.ts +47 -0
  14. package/dist/helpers/comment.js +116 -0
  15. package/dist/helpers/content.d.ts +3 -0
  16. package/dist/helpers/content.js +8 -0
  17. package/dist/helpers/delete.d.ts +3 -0
  18. package/dist/helpers/delete.js +7 -0
  19. package/dist/helpers/emoji.d.ts +11 -0
  20. package/dist/helpers/emoji.js +16 -0
  21. package/dist/helpers/event.d.ts +48 -0
  22. package/dist/helpers/event.js +105 -0
  23. package/dist/helpers/external-id.d.ts +29 -0
  24. package/dist/helpers/external-id.js +20 -0
  25. package/dist/helpers/file-metadata.d.ts +53 -0
  26. package/dist/helpers/file-metadata.js +90 -0
  27. package/dist/helpers/file-metadata.test.d.ts +1 -0
  28. package/dist/helpers/file-metadata.test.js +103 -0
  29. package/dist/helpers/filter.d.ts +10 -0
  30. package/dist/helpers/filter.js +46 -0
  31. package/dist/helpers/groups.d.ts +14 -0
  32. package/dist/helpers/groups.js +16 -0
  33. package/dist/helpers/hashtag.d.ts +2 -0
  34. package/dist/helpers/hashtag.js +7 -0
  35. package/dist/helpers/hidden-tags.d.ts +48 -0
  36. package/dist/helpers/hidden-tags.js +108 -0
  37. package/dist/helpers/hidden-tags.test.d.ts +1 -0
  38. package/dist/helpers/hidden-tags.test.js +28 -0
  39. package/dist/helpers/index.d.ts +28 -0
  40. package/dist/helpers/index.js +28 -0
  41. package/dist/helpers/json.d.ts +2 -0
  42. package/dist/helpers/json.js +9 -0
  43. package/dist/helpers/lnurl.d.ts +4 -0
  44. package/dist/helpers/lnurl.js +40 -0
  45. package/dist/helpers/lru.d.ts +32 -0
  46. package/dist/helpers/lru.js +148 -0
  47. package/dist/helpers/mailboxes.d.ts +11 -0
  48. package/dist/helpers/mailboxes.js +36 -0
  49. package/dist/helpers/mailboxes.test.d.ts +1 -0
  50. package/dist/helpers/mailboxes.test.js +81 -0
  51. package/dist/helpers/picture-post.d.ts +4 -0
  52. package/dist/helpers/picture-post.js +6 -0
  53. package/dist/helpers/pointers.d.ts +55 -0
  54. package/dist/helpers/pointers.js +205 -0
  55. package/dist/helpers/profile.d.ts +20 -0
  56. package/dist/helpers/profile.js +31 -0
  57. package/dist/helpers/relays.d.ts +12 -0
  58. package/dist/helpers/relays.js +31 -0
  59. package/dist/helpers/share.d.ts +4 -0
  60. package/dist/helpers/share.js +12 -0
  61. package/dist/helpers/string.d.ts +10 -0
  62. package/dist/helpers/string.js +15 -0
  63. package/dist/helpers/tags.d.ts +25 -0
  64. package/dist/helpers/tags.js +42 -0
  65. package/dist/helpers/tags.test.d.ts +1 -0
  66. package/dist/helpers/tags.test.js +16 -0
  67. package/dist/helpers/threading.d.ts +55 -0
  68. package/dist/helpers/threading.js +94 -0
  69. package/dist/helpers/threading.test.d.ts +1 -0
  70. package/dist/helpers/threading.test.js +41 -0
  71. package/dist/helpers/time.d.ts +2 -0
  72. package/dist/helpers/time.js +4 -0
  73. package/dist/helpers/url.d.ts +14 -0
  74. package/dist/helpers/url.js +30 -0
  75. package/dist/helpers/zap.d.ts +39 -0
  76. package/dist/helpers/zap.js +95 -0
  77. package/dist/index.d.ts +5 -0
  78. package/dist/index.js +5 -0
  79. package/dist/logger.d.ts +2 -0
  80. package/dist/logger.js +2 -0
  81. package/dist/observable/get-value.d.ts +3 -0
  82. package/dist/observable/get-value.js +14 -0
  83. package/dist/observable/index.d.ts +2 -0
  84. package/dist/observable/index.js +2 -0
  85. package/dist/observable/share-latest-value.d.ts +8 -0
  86. package/dist/observable/share-latest-value.js +21 -0
  87. package/dist/promise/deferred.d.ts +6 -0
  88. package/dist/promise/deferred.js +15 -0
  89. package/dist/promise/index.d.ts +1 -0
  90. package/dist/promise/index.js +1 -0
  91. package/dist/queries/comments.d.ts +4 -0
  92. package/dist/queries/comments.js +14 -0
  93. package/dist/queries/index.d.ts +7 -0
  94. package/dist/queries/index.js +7 -0
  95. package/dist/queries/mailboxes.d.ts +6 -0
  96. package/dist/queries/mailboxes.js +13 -0
  97. package/dist/queries/profile.d.ts +4 -0
  98. package/dist/queries/profile.js +12 -0
  99. package/dist/queries/reactions.d.ts +4 -0
  100. package/dist/queries/reactions.js +19 -0
  101. package/dist/queries/simple.d.ts +16 -0
  102. package/dist/queries/simple.js +38 -0
  103. package/dist/queries/thread.d.ts +25 -0
  104. package/dist/queries/thread.js +92 -0
  105. package/dist/queries/zaps.d.ts +5 -0
  106. package/dist/queries/zaps.js +21 -0
  107. package/dist/query-store/index.d.ts +57 -0
  108. package/dist/query-store/index.js +68 -0
  109. package/package.json +1 -1
@@ -0,0 +1,389 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { insertEventIntoDescendingList } from "nostr-tools/utils";
3
+ import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
4
+ import { Observable } from "rxjs";
5
+ import { Database } from "./database.js";
6
+ import { getEventUID, getReplaceableUID, getTagValue, isReplaceable } from "../helpers/event.js";
7
+ import { matchFilters } from "../helpers/filter.js";
8
+ import { addSeenRelay } from "../helpers/relays.js";
9
+ import { getDeleteCoordinates, getDeleteIds } from "../helpers/delete.js";
10
+ export class EventStore {
11
+ database;
12
+ /** Enable this to keep old versions of replaceable events */
13
+ keepOldVersions = false;
14
+ constructor() {
15
+ this.database = new Database();
16
+ }
17
+ /** Adds an event to the database and update subscriptions */
18
+ add(event, fromRelay) {
19
+ if (event.kind === kinds.EventDeletion)
20
+ this.handleDeleteEvent(event);
21
+ // ignore if the event was deleted
22
+ if (this.checkDeleted(event))
23
+ return event;
24
+ // insert event into database
25
+ const inserted = this.database.addEvent(event);
26
+ // remove all old version of the replaceable event
27
+ if (!this.keepOldVersions && isReplaceable(event.kind)) {
28
+ const current = this.database.getReplaceable(event.kind, event.pubkey, getTagValue(event, "d"));
29
+ if (current) {
30
+ const older = Array.from(current).filter((e) => e.created_at < event.created_at);
31
+ for (const old of older)
32
+ this.database.deleteEvent(old);
33
+ // skip inserting this event because its not the newest
34
+ if (current.length !== older.length)
35
+ return current[0];
36
+ }
37
+ }
38
+ // attach relay this event was from
39
+ if (fromRelay)
40
+ addSeenRelay(inserted, fromRelay);
41
+ return inserted;
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
+ }
53
+ deletedIds = new Set();
54
+ deletedCoords = new Map();
55
+ handleDeleteEvent(deleteEvent) {
56
+ const ids = getDeleteIds(deleteEvent);
57
+ for (const id of ids) {
58
+ this.deletedIds.add(id);
59
+ // remove deleted events in the database
60
+ const event = this.database.getEvent(id);
61
+ if (event)
62
+ this.database.deleteEvent(event);
63
+ }
64
+ const coords = getDeleteCoordinates(deleteEvent);
65
+ for (const coord of coords) {
66
+ this.deletedCoords.set(coord, Math.max(this.deletedCoords.get(coord) ?? 0, deleteEvent.created_at));
67
+ // remove deleted events in the database
68
+ const event = this.database.getEvent(coord);
69
+ if (event && event.created_at < deleteEvent.created_at)
70
+ this.database.deleteEvent(event);
71
+ }
72
+ }
73
+ checkDeleted(event) {
74
+ if (this.deletedIds.has(event.id))
75
+ return true;
76
+ if (isParameterizedReplaceableKind(event.kind)) {
77
+ const deleted = this.deletedCoords.get(getEventUID(event));
78
+ if (deleted)
79
+ return deleted > event.created_at;
80
+ }
81
+ return false;
82
+ }
83
+ /** Removes any event that is not being used by a subscription */
84
+ prune(max) {
85
+ return this.database.prune(max);
86
+ }
87
+ /** Add an event to the store and notifies all subscribes it has updated */
88
+ update(event) {
89
+ return this.database.updateEvent(event);
90
+ }
91
+ getAll(filters) {
92
+ return this.database.getForFilters(filters);
93
+ }
94
+ hasEvent(uid) {
95
+ return this.database.hasEvent(uid);
96
+ }
97
+ getEvent(uid) {
98
+ return this.database.getEvent(uid);
99
+ }
100
+ hasReplaceable(kind, pubkey, d) {
101
+ return this.database.hasReplaceable(kind, pubkey, d);
102
+ }
103
+ /** Gets the latest version of a replaceable event */
104
+ getReplaceable(kind, pubkey, d) {
105
+ return this.database.getReplaceable(kind, pubkey, d)?.[0];
106
+ }
107
+ /** Returns all versions of a replaceable event */
108
+ getReplaceableHistory(kind, pubkey, d) {
109
+ return this.database.getReplaceable(kind, pubkey, d);
110
+ }
111
+ /** Creates an observable that updates a single event */
112
+ event(id) {
113
+ return new Observable((observer) => {
114
+ let current = this.database.getEvent(id);
115
+ if (current) {
116
+ observer.next(current);
117
+ this.database.claimEvent(current, observer);
118
+ }
119
+ // subscribe to future events
120
+ const inserted = this.database.inserted.subscribe((event) => {
121
+ if (event.id === id) {
122
+ current = event;
123
+ observer.next(event);
124
+ this.database.claimEvent(event, observer);
125
+ }
126
+ });
127
+ // subscribe to updated events
128
+ const updated = this.database.updated.subscribe((event) => {
129
+ if (event.id === id)
130
+ observer.next(current);
131
+ });
132
+ // subscribe to deleted events
133
+ const deleted = this.database.deleted.subscribe((event) => {
134
+ if (current?.id === event.id) {
135
+ this.database.removeClaim(current, observer);
136
+ current = undefined;
137
+ observer.next(undefined);
138
+ }
139
+ });
140
+ return () => {
141
+ deleted.unsubscribe();
142
+ updated.unsubscribe();
143
+ inserted.unsubscribe();
144
+ if (current)
145
+ this.database.removeClaim(current, observer);
146
+ };
147
+ });
148
+ }
149
+ /** Creates an observable that subscribes to multiple events */
150
+ events(ids) {
151
+ return new Observable((observer) => {
152
+ let events = {};
153
+ for (const id of ids) {
154
+ const event = this.getEvent(id);
155
+ if (event) {
156
+ events = { ...events, [id]: event };
157
+ this.database.claimEvent(event, observer);
158
+ }
159
+ }
160
+ observer.next(events);
161
+ // subscribe to future events
162
+ const inserted = this.database.inserted.subscribe((event) => {
163
+ const id = event.id;
164
+ if (ids.includes(id) && !events[id]) {
165
+ events = { ...events, [id]: event };
166
+ observer.next(events);
167
+ // claim new event
168
+ this.database.claimEvent(event, observer);
169
+ }
170
+ });
171
+ // subscribe to updated events
172
+ const updated = this.database.updated.subscribe((event) => {
173
+ if (ids.includes(event.id))
174
+ observer.next(events);
175
+ });
176
+ // subscribe to deleted events
177
+ const deleted = this.database.deleted.subscribe((event) => {
178
+ const id = event.id;
179
+ if (ids.includes(id)) {
180
+ const current = events[id];
181
+ if (current) {
182
+ this.database.removeClaim(current, observer);
183
+ delete events[id];
184
+ observer.next(events);
185
+ }
186
+ }
187
+ });
188
+ return () => {
189
+ inserted.unsubscribe();
190
+ deleted.unsubscribe();
191
+ updated.unsubscribe();
192
+ for (const [_uid, event] of Object.entries(events)) {
193
+ this.database.removeClaim(event, observer);
194
+ }
195
+ };
196
+ });
197
+ }
198
+ /** Creates an observable with the latest version of a replaceable event */
199
+ replaceable(kind, pubkey, d) {
200
+ return new Observable((observer) => {
201
+ const uid = getReplaceableUID(kind, pubkey, d);
202
+ // get latest version
203
+ let current = this.database.getReplaceable(kind, pubkey, d)?.[0];
204
+ if (current) {
205
+ observer.next(current);
206
+ this.database.claimEvent(current, observer);
207
+ }
208
+ // subscribe to future events
209
+ const inserted = this.database.inserted.subscribe((event) => {
210
+ if (getEventUID(event) === uid && (!current || event.created_at > current.created_at)) {
211
+ // remove old claim
212
+ if (current)
213
+ this.database.removeClaim(current, observer);
214
+ current = event;
215
+ observer.next(event);
216
+ // claim new event
217
+ this.database.claimEvent(current, observer);
218
+ }
219
+ });
220
+ // subscribe to updated events
221
+ const updated = this.database.updated.subscribe((event) => {
222
+ if (event === current)
223
+ observer.next(event);
224
+ });
225
+ // subscribe to deleted events
226
+ const deleted = this.database.deleted.subscribe((event) => {
227
+ if (getEventUID(event) === uid && event === current) {
228
+ this.database.removeClaim(current, observer);
229
+ current = undefined;
230
+ observer.next(undefined);
231
+ }
232
+ });
233
+ return () => {
234
+ inserted.unsubscribe();
235
+ deleted.unsubscribe();
236
+ updated.unsubscribe();
237
+ if (current)
238
+ this.database.removeClaim(current, observer);
239
+ };
240
+ });
241
+ }
242
+ /** Creates an observable with the latest versions of replaceable events */
243
+ replaceableSet(pointers) {
244
+ return new Observable((observer) => {
245
+ const coords = pointers.map((p) => getReplaceableUID(p.kind, p.pubkey, p.identifier));
246
+ let events = {};
247
+ const handleEvent = (event) => {
248
+ const uid = getEventUID(event);
249
+ const current = events[uid];
250
+ if (current) {
251
+ if (event.created_at > current.created_at) {
252
+ this.database.removeClaim(current, observer);
253
+ }
254
+ else
255
+ return;
256
+ }
257
+ events = { ...events, [uid]: event };
258
+ this.database.claimEvent(event, observer);
259
+ };
260
+ // get latest version
261
+ for (const pointer of pointers) {
262
+ const events = this.database.getReplaceable(pointer.kind, pointer.pubkey, pointer.identifier);
263
+ if (events)
264
+ handleEvent(events[0]);
265
+ }
266
+ observer.next(events);
267
+ // subscribe to future events
268
+ const inserted = this.database.inserted.subscribe((event) => {
269
+ if (isReplaceable(event.kind) && coords.includes(getEventUID(event))) {
270
+ handleEvent(event);
271
+ observer.next(events);
272
+ }
273
+ });
274
+ // subscribe to updated events
275
+ const updated = this.database.updated.subscribe((event) => {
276
+ if (isReplaceable(event.kind) && coords.includes(getEventUID(event))) {
277
+ observer.next(events);
278
+ }
279
+ });
280
+ // subscribe to deleted events
281
+ const deleted = this.database.deleted.subscribe((event) => {
282
+ const uid = getEventUID(event);
283
+ if (events[uid]) {
284
+ delete events[uid];
285
+ this.database.removeClaim(event, observer);
286
+ observer.next(events);
287
+ }
288
+ });
289
+ return () => {
290
+ inserted.unsubscribe();
291
+ deleted.unsubscribe();
292
+ updated.unsubscribe();
293
+ for (const [_id, event] of Object.entries(events)) {
294
+ this.database.removeClaim(event, observer);
295
+ }
296
+ };
297
+ });
298
+ }
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];
306
+ return new Observable((observer) => {
307
+ if (!onlyNew) {
308
+ let events = this.database.getForFilters(filters);
309
+ for (const event of events)
310
+ observer.next(event);
311
+ }
312
+ // subscribe to future events
313
+ const sub = this.database.inserted.subscribe((event) => {
314
+ if (matchFilters(filters, event))
315
+ observer.next(event);
316
+ });
317
+ return () => sub.unsubscribe();
318
+ });
319
+ }
320
+ /** Creates an observable that updates with an array of sorted events */
321
+ timeline(filters, keepOldVersions = false) {
322
+ filters = Array.isArray(filters) ? filters : [filters];
323
+ return new Observable((observer) => {
324
+ const seen = new Map();
325
+ const timeline = [];
326
+ // NOTE: only call this if we know the event is in timeline
327
+ const removeFromTimeline = (event) => {
328
+ timeline.splice(timeline.indexOf(event), 1);
329
+ if (!keepOldVersions && isReplaceable(event.kind))
330
+ seen.delete(getEventUID(event));
331
+ this.database.removeClaim(event, observer);
332
+ };
333
+ // inserts an event into the timeline and handles replaceable events
334
+ const insertIntoTimeline = (event) => {
335
+ // remove old versions
336
+ if (!keepOldVersions && isReplaceable(event.kind)) {
337
+ const uid = getEventUID(event);
338
+ const old = seen.get(uid);
339
+ if (old) {
340
+ if (event.created_at > old.created_at)
341
+ removeFromTimeline(old);
342
+ else
343
+ return;
344
+ }
345
+ seen.set(uid, event);
346
+ }
347
+ // insert into timeline
348
+ insertEventIntoDescendingList(timeline, event);
349
+ this.database.claimEvent(event, observer);
350
+ };
351
+ // build initial timeline
352
+ const events = this.database.getForFilters(filters);
353
+ for (const event of events)
354
+ insertIntoTimeline(event);
355
+ observer.next([...timeline]);
356
+ // subscribe to future events
357
+ const inserted = this.database.inserted.subscribe((event) => {
358
+ if (matchFilters(filters, event)) {
359
+ insertIntoTimeline(event);
360
+ observer.next([...timeline]);
361
+ }
362
+ });
363
+ // subscribe to updated events
364
+ const updated = this.database.updated.subscribe((event) => {
365
+ if (timeline.includes(event)) {
366
+ observer.next([...timeline]);
367
+ }
368
+ });
369
+ // subscribe to deleted events
370
+ const deleted = this.database.deleted.subscribe((event) => {
371
+ if (timeline.includes(event)) {
372
+ removeFromTimeline(event);
373
+ observer.next([...timeline]);
374
+ }
375
+ });
376
+ return () => {
377
+ inserted.unsubscribe();
378
+ deleted.unsubscribe();
379
+ updated.unsubscribe();
380
+ // remove all claims
381
+ for (const event of timeline) {
382
+ this.database.removeClaim(event, observer);
383
+ }
384
+ // forget seen replaceable events
385
+ seen.clear();
386
+ };
387
+ });
388
+ }
389
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./event-store.js";
2
+ export * from "./database.js";
@@ -0,0 +1,2 @@
1
+ export * from "./event-store.js";
2
+ export * from "./database.js";
@@ -0,0 +1,9 @@
1
+ export type ParsedInvoice = {
2
+ paymentRequest: string;
3
+ description: string;
4
+ amount?: number;
5
+ timestamp: number;
6
+ expiry: number;
7
+ };
8
+ /** Parses a lightning invoice */
9
+ export declare function parseBolt11(paymentRequest: string): ParsedInvoice;
@@ -0,0 +1,15 @@
1
+ import { decode } from "light-bolt11-decoder";
2
+ /** Parses a lightning invoice */
3
+ export function parseBolt11(paymentRequest) {
4
+ const decoded = decode(paymentRequest);
5
+ const timestamp = decoded.sections.find((s) => s.name === "timestamp")?.value ?? 0;
6
+ const description = decoded.sections.find((s) => s.name === "description")?.value ?? "";
7
+ const amount = parseInt(decoded.sections.find((s) => s.name === "amount")?.value ?? "0");
8
+ return {
9
+ paymentRequest: decoded.paymentRequest,
10
+ description: description,
11
+ amount: amount,
12
+ timestamp: timestamp,
13
+ expiry: timestamp + decoded.expiry,
14
+ };
15
+ }
@@ -0,0 +1,5 @@
1
+ import { EventTemplate, NostrEvent } from "nostr-tools";
2
+ export declare function getCachedValue<T extends unknown>(event: NostrEvent | EventTemplate, symbol: symbol): T | undefined;
3
+ export declare function setCachedValue<T extends unknown>(event: NostrEvent | EventTemplate, symbol: symbol, value: T): void;
4
+ /** Internal method used to cache computed values on events */
5
+ export declare function getOrComputeCachedValue<T extends unknown>(event: NostrEvent | EventTemplate, symbol: symbol, compute: (event: NostrEvent | EventTemplate) => T): T;
@@ -0,0 +1,17 @@
1
+ export function getCachedValue(event, symbol) {
2
+ return Reflect.get(event, symbol);
3
+ }
4
+ export function setCachedValue(event, symbol, value) {
5
+ Reflect.set(event, symbol, value);
6
+ }
7
+ /** Internal method used to cache computed values on events */
8
+ export function getOrComputeCachedValue(event, symbol, compute) {
9
+ if (Reflect.has(event, symbol)) {
10
+ return Reflect.get(event, symbol);
11
+ }
12
+ else {
13
+ const value = compute(event);
14
+ Reflect.set(event, symbol, value);
15
+ return value;
16
+ }
17
+ }
@@ -0,0 +1,47 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { ExternalPointer, ExternalIdentifiers } from "./external-id.js";
3
+ export declare const COMMENT_KIND = 1111;
4
+ export type CommentEventPointer = {
5
+ id: string;
6
+ kind: number;
7
+ pubkey?: string;
8
+ relay?: string;
9
+ };
10
+ export type CommentAddressPointer = {
11
+ id?: string;
12
+ kind: number;
13
+ pubkey: string;
14
+ identifier: string;
15
+ relay?: string;
16
+ };
17
+ export type CommentExternalPointer = ExternalPointer<keyof ExternalIdentifiers>;
18
+ export type CommentPointer = CommentEventPointer | CommentAddressPointer | CommentExternalPointer;
19
+ export declare const CommentRootPointerSymbol: unique symbol;
20
+ export declare const CommentReplyPointerSymbol: unique symbol;
21
+ /**
22
+ * Gets the EventPointer from an array of tags
23
+ * @throws
24
+ */
25
+ export declare function getCommentEventPointer(tags: string[][], root?: boolean): CommentEventPointer | null;
26
+ /**
27
+ * Gets the AddressPointer from an array of tags
28
+ * @throws
29
+ */
30
+ export declare function getCommentAddressPointer(tags: string[][], root?: boolean): CommentAddressPointer | null;
31
+ /**
32
+ * Gets the ExternalPointer from an array of tags
33
+ * @throws
34
+ */
35
+ export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer | null;
36
+ /**
37
+ * Returns the root pointer for a comment
38
+ * @throws
39
+ */
40
+ export declare function getCommentRootPointer(comment: NostrEvent): CommentPointer | null;
41
+ /**
42
+ * Returns the reply pointer for a comment
43
+ * @throws
44
+ */
45
+ export declare function getCommentReplyPointer(comment: NostrEvent): CommentPointer | null;
46
+ export declare function isCommentEventPointer(pointer: any): pointer is CommentEventPointer;
47
+ export declare function isCommentAddressPointer(pointer: any): pointer is CommentAddressPointer;
@@ -0,0 +1,116 @@
1
+ import { getExternalPointerFromTag } from "./external-id.js";
2
+ import { getOrComputeCachedValue } from "./cache.js";
3
+ import { getAddressPointerFromATag } from "./pointers.js";
4
+ import { safeRelayUrl } from "./relays.js";
5
+ export const COMMENT_KIND = 1111;
6
+ export const CommentRootPointerSymbol = Symbol.for("comment-root-pointer");
7
+ export const CommentReplyPointerSymbol = Symbol.for("comment-reply-pointer");
8
+ /**
9
+ * Gets the EventPointer from an array of tags
10
+ * @throws
11
+ */
12
+ export function getCommentEventPointer(tags, root = false) {
13
+ const tag = tags.find((t) => t[0] === (root ? "E" : "e"));
14
+ const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
15
+ if (tag) {
16
+ if (!kind)
17
+ throw new Error("Missing kind tag");
18
+ const pointer = {
19
+ id: tag[1],
20
+ kind: parseInt(kind),
21
+ pubkey: tag[3] || undefined,
22
+ relay: tag[2] && (safeRelayUrl(tag[2]) ?? undefined),
23
+ };
24
+ return pointer;
25
+ }
26
+ return null;
27
+ }
28
+ /**
29
+ * Gets the AddressPointer from an array of tags
30
+ * @throws
31
+ */
32
+ export function getCommentAddressPointer(tags, root = false) {
33
+ const tag = tags.find((t) => t[0] === (root ? "A" : "a"));
34
+ const id = tags.find((t) => t[0] === (root ? "E" : "e"))?.[1];
35
+ const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
36
+ if (tag) {
37
+ if (!kind)
38
+ throw new Error("Missing kind tag");
39
+ const pointer = {
40
+ id,
41
+ ...getAddressPointerFromATag(tag),
42
+ kind: parseInt(kind),
43
+ };
44
+ return pointer;
45
+ }
46
+ return null;
47
+ }
48
+ /**
49
+ * Gets the ExternalPointer from an array of tags
50
+ * @throws
51
+ */
52
+ export function getCommentExternalPointer(tags, root = false) {
53
+ const tag = tags.find((t) => t[0] === (root ? "I" : "i"));
54
+ const kind = tags.find((t) => t[0] === (root ? "K" : "k"))?.[1];
55
+ if (tag) {
56
+ if (!kind)
57
+ throw new Error("Missing kind tag");
58
+ const pointer = getExternalPointerFromTag(tag);
59
+ return pointer;
60
+ }
61
+ return null;
62
+ }
63
+ /**
64
+ * Returns the root pointer for a comment
65
+ * @throws
66
+ */
67
+ export function getCommentRootPointer(comment) {
68
+ if (comment.kind !== COMMENT_KIND)
69
+ throw new Error("Event is not a comment");
70
+ return getOrComputeCachedValue(comment, CommentRootPointerSymbol, () => {
71
+ // check for address pointer first since it can also have E tags
72
+ const A = getCommentAddressPointer(comment.tags, true);
73
+ if (A)
74
+ return A;
75
+ const E = getCommentEventPointer(comment.tags, true);
76
+ if (E)
77
+ return E;
78
+ const I = getCommentExternalPointer(comment.tags, true);
79
+ if (I)
80
+ return I;
81
+ return null;
82
+ });
83
+ }
84
+ /**
85
+ * Returns the reply pointer for a comment
86
+ * @throws
87
+ */
88
+ export function getCommentReplyPointer(comment) {
89
+ if (comment.kind !== COMMENT_KIND)
90
+ throw new Error("Event is not a comment");
91
+ return getOrComputeCachedValue(comment, CommentReplyPointerSymbol, () => {
92
+ // check for address pointer first since it can also have E tags
93
+ const A = getCommentAddressPointer(comment.tags, false);
94
+ if (A)
95
+ return A;
96
+ const E = getCommentEventPointer(comment.tags, false);
97
+ if (E)
98
+ return E;
99
+ const I = getCommentExternalPointer(comment.tags, false);
100
+ if (I)
101
+ return I;
102
+ return null;
103
+ });
104
+ }
105
+ export function isCommentEventPointer(pointer) {
106
+ return (Reflect.has(pointer, "id") &&
107
+ Reflect.has(pointer, "kind") &&
108
+ !Reflect.has(pointer, "identifier") &&
109
+ typeof pointer.kind === "number");
110
+ }
111
+ export function isCommentAddressPointer(pointer) {
112
+ return (Reflect.has(pointer, "identifier") &&
113
+ Reflect.has(pointer, "pubkey") &&
114
+ Reflect.has(pointer, "kind") &&
115
+ typeof pointer.kind === "number");
116
+ }
@@ -0,0 +1,3 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ /** Returns the NIP-36 content-warning for an event. returns boolean if there is no "reason" */
3
+ export declare function getContentWarning(event: NostrEvent): string | boolean;
@@ -0,0 +1,8 @@
1
+ /** Returns the NIP-36 content-warning for an event. returns boolean if there is no "reason" */
2
+ export function getContentWarning(event) {
3
+ const tag = event.tags.find((t) => t[0] === "content-warning");
4
+ if (tag)
5
+ return tag[1] || true;
6
+ else
7
+ return false;
8
+ }
@@ -0,0 +1,3 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ export declare function getDeleteIds(deleteEvent: NostrEvent): string[];
3
+ export declare function getDeleteCoordinates(deleteEvent: NostrEvent): string[];
@@ -0,0 +1,7 @@
1
+ import { isATag, isETag } from "./tags.js";
2
+ export function getDeleteIds(deleteEvent) {
3
+ return deleteEvent.tags.filter(isETag).map((t) => t[1]);
4
+ }
5
+ export function getDeleteCoordinates(deleteEvent) {
6
+ return deleteEvent.tags.filter(isATag).map((t) => t[1]);
7
+ }
@@ -0,0 +1,11 @@
1
+ import { EventTemplate, NostrEvent } from "nostr-tools";
2
+ /** Gets an "emoji" tag that matches an emoji code */
3
+ export declare function getEmojiTag(event: NostrEvent | EventTemplate, code: string): ["emoji", string, string] | undefined;
4
+ /** Returns the name of a NIP-30 emoji pack */
5
+ export declare function getPackName(pack: NostrEvent): string | undefined;
6
+ export type Emoji = {
7
+ name: string;
8
+ url: string;
9
+ };
10
+ /** Returns an array of emojis from a NIP-30 emoji pack */
11
+ export declare function getEmojis(pack: NostrEvent): Emoji[];
@@ -0,0 +1,16 @@
1
+ import { getTagValue } from "./event.js";
2
+ /** Gets an "emoji" tag that matches an emoji code */
3
+ export function getEmojiTag(event, code) {
4
+ code = code.replace(/^:|:$/g, "").toLocaleLowerCase();
5
+ return event.tags.filter((t) => t[0] === "emoji" && t[1] && t[2]).find((t) => t[1].toLowerCase() === code);
6
+ }
7
+ /** Returns the name of a NIP-30 emoji pack */
8
+ export function getPackName(pack) {
9
+ return getTagValue(pack, "title") || getTagValue(pack, "d");
10
+ }
11
+ /** Returns an array of emojis from a NIP-30 emoji pack */
12
+ export function getEmojis(pack) {
13
+ return pack.tags
14
+ .filter((t) => t[0] === "emoji" && t[1] && t[2])
15
+ .map((t) => ({ name: t[1], url: t[2] }));
16
+ }