applesauce-core 0.0.0-next-20241128172721 → 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.
Files changed (76) hide show
  1. package/dist/event-store/event-store.d.ts +13 -5
  2. package/dist/event-store/event-store.js +31 -22
  3. package/dist/helpers/emoji.d.ts +2 -1
  4. package/dist/helpers/emoji.js +1 -0
  5. package/dist/helpers/event.d.ts +5 -0
  6. package/dist/helpers/event.js +16 -0
  7. package/dist/helpers/hidden-tags.d.ts +13 -4
  8. package/dist/helpers/hidden-tags.js +43 -25
  9. package/dist/helpers/pointers.d.ts +13 -0
  10. package/dist/helpers/pointers.js +49 -5
  11. package/dist/helpers/tags.d.ts +6 -0
  12. package/dist/helpers/tags.js +6 -0
  13. package/dist/helpers/url.d.ts +4 -1
  14. package/dist/helpers/url.js +4 -3
  15. package/dist/helpers/zap.d.ts +17 -0
  16. package/dist/helpers/zap.js +17 -0
  17. package/dist/observable/get-value.d.ts +1 -0
  18. package/dist/observable/get-value.js +1 -0
  19. package/dist/promise/deferred.d.ts +1 -0
  20. package/dist/promise/deferred.js +1 -0
  21. package/dist/queries/mailboxes.d.ts +1 -0
  22. package/dist/queries/mailboxes.js +1 -0
  23. package/dist/queries/profile.d.ts +1 -0
  24. package/dist/queries/profile.js +1 -0
  25. package/dist/queries/reactions.d.ts +1 -1
  26. package/dist/queries/reactions.js +1 -1
  27. package/dist/queries/simple.js +0 -2
  28. package/dist/queries/thread.d.ts +2 -0
  29. package/dist/queries/thread.js +28 -3
  30. package/dist/queries/zaps.d.ts +1 -0
  31. package/dist/queries/zaps.js +1 -0
  32. package/dist/query-store/index.d.ts +18 -10
  33. package/dist/query-store/index.js +33 -34
  34. package/package.json +1 -1
  35. package/dist/helpers/channel.d.ts +0 -15
  36. package/dist/helpers/channel.js +0 -27
  37. package/dist/helpers/mute.d.ts +0 -21
  38. package/dist/helpers/mute.js +0 -52
  39. package/dist/helpers/symbols.d.ts +0 -6
  40. package/dist/helpers/symbols.js +0 -2
  41. package/dist/helpers/user-status.d.ts +0 -22
  42. package/dist/helpers/user-status.js +0 -24
  43. package/dist/observable/getValue.d.ts +0 -2
  44. package/dist/observable/getValue.js +0 -13
  45. package/dist/observable/stateful.d.ts +0 -10
  46. package/dist/observable/stateful.js +0 -60
  47. package/dist/observable/throttle.d.ts +0 -3
  48. package/dist/observable/throttle.js +0 -23
  49. package/dist/queries/channel.d.ts +0 -11
  50. package/dist/queries/channel.js +0 -72
  51. package/dist/queries/mute.d.ts +0 -7
  52. package/dist/queries/mute.js +0 -16
  53. package/dist/queries/user-status.d.ts +0 -11
  54. package/dist/queries/user-status.js +0 -35
  55. package/dist/query-store/queries/TimelineQuery.d.ts +0 -1
  56. package/dist/query-store/queries/TimelineQuery.js +0 -1
  57. package/dist/query-store/queries/channel.d.ts +0 -11
  58. package/dist/query-store/queries/channel.js +0 -72
  59. package/dist/query-store/queries/index.d.ts +0 -7
  60. package/dist/query-store/queries/index.js +0 -7
  61. package/dist/query-store/queries/mailboxes.d.ts +0 -5
  62. package/dist/query-store/queries/mailboxes.js +0 -11
  63. package/dist/query-store/queries/mute.d.ts +0 -7
  64. package/dist/query-store/queries/mute.js +0 -16
  65. package/dist/query-store/queries/profile.d.ts +0 -3
  66. package/dist/query-store/queries/profile.js +0 -10
  67. package/dist/query-store/queries/reactions.d.ts +0 -4
  68. package/dist/query-store/queries/reactions.js +0 -19
  69. package/dist/query-store/queries/simple.d.ts +0 -5
  70. package/dist/query-store/queries/simple.js +0 -20
  71. package/dist/query-store/queries/thread.d.ts +0 -20
  72. package/dist/query-store/queries/thread.js +0 -60
  73. package/dist/query-store/queries/timeline.d.ts +0 -3
  74. package/dist/query-store/queries/timeline.js +0 -3
  75. package/dist/utils/lru.d.ts +0 -32
  76. package/dist/utils/lru.js +0 -148
@@ -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
- /** Whether to keep old versions of replaceable events */
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
- /** Creates an observable that streams all events that match the filter */
38
- stream(filters: Filter[]): Observable<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>;
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
- /** Whether to keep old versions of replaceable events */
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
- /** Creates an observable that streams all events that match the filter */
286
- stream(filters) {
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
- let claimed = new Set();
289
- let events = this.database.getForFilters(filters);
290
- for (const event of events) {
291
- observer.next(event);
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 = this.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 = [];
@@ -1,5 +1,6 @@
1
1
  import { EventTemplate, NostrEvent } from "nostr-tools";
2
- export declare function getEmojiTag(event: NostrEvent | EventTemplate, code: string): ["emoji", string, string];
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 */
@@ -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);
@@ -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 )
@@ -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
- export declare const EventsWithHiddenTags: number[];
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(event: NostrEvent | EventTemplate): boolean;
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 from an event if they are unlocked */
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
- export const EventsWithHiddenTags = [
5
- 37375, // NIP-60 wallet
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(event) {
24
- return EventsWithHiddenTags.includes(event.kind);
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 from an event if they are unlocked */
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
- const plaintext = await signer.nip04.decrypt(event.pubkey, event.content);
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 can not have hidden tags");
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
- draft.content = await signer.nip04.encrypt(event.pubkey, JSON.stringify(newHidden));
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
- const ciphertext = await signer.nip04.encrypt(event.pubkey, JSON.stringify(hidden));
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,
@@ -1,7 +1,9 @@
1
1
  import { AddressPointer, DecodeResult, EventPointer, ProfilePointer } from "nostr-tools/nip19";
2
+ import { NostrEvent } from "nostr-tools";
2
3
  export type AddressPointerWithoutD = Omit<AddressPointer, "identifier"> & {
3
4
  identifier?: string;
4
5
  };
6
+ /** Parse the value of an "a" tag into an AddressPointer */
5
7
  export declare function parseCoordinate(a: string): AddressPointerWithoutD | null;
6
8
  export declare function parseCoordinate(a: string, requireD: false): AddressPointerWithoutD | null;
7
9
  export declare function parseCoordinate(a: string, requireD: true): AddressPointer | null;
@@ -9,14 +11,25 @@ export declare function parseCoordinate(a: string, requireD: false, silent: fals
9
11
  export declare function parseCoordinate(a: string, requireD: true, silent: false): AddressPointer;
10
12
  export declare function parseCoordinate(a: string, requireD: true, silent: true): AddressPointer | null;
11
13
  export declare function parseCoordinate(a: string, requireD: false, silent: true): AddressPointerWithoutD | null;
14
+ /** Extra a pubkey from the result of nip19.decode */
12
15
  export declare function getPubkeyFromDecodeResult(result?: DecodeResult): string | undefined;
16
+ /** Encodes the result of nip19.decode */
13
17
  export declare function encodeDecodeResult(result: DecodeResult): "" | `nprofile1${string}` | `nevent1${string}` | `naddr1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
18
+ /** @throws */
14
19
  export declare function getEventPointerFromTag(tag: string[]): EventPointer;
20
+ /** @throws */
15
21
  export declare function getAddressPointerFromTag(tag: string[]): AddressPointer;
22
+ /** @throws */
16
23
  export declare function getProfilePointerFromTag(tag: string[]): ProfilePointer;
24
+ /** Parses "e", "a", "p", and "q" tags into a pointer */
17
25
  export declare function getPointerFromTag(tag: string[]): DecodeResult | null;
18
26
  export declare function isAddressPointer(pointer: DecodeResult["data"]): pointer is AddressPointer;
19
27
  export declare function isEventPointer(pointer: DecodeResult["data"]): pointer is EventPointer;
28
+ /** Returns the coordinate string for an AddressPointer */
20
29
  export declare function getCoordinateFromAddressPointer(pointer: AddressPointer): string;
30
+ /** Returns a tag for an address pointer */
21
31
  export declare function getATagFromAddressPointer(pointer: AddressPointer): ["a", ...string[]];
32
+ /** Returns a tag for an event pointer */
22
33
  export declare function getETagFromEventPointer(pointer: EventPointer): ["e", ...string[]];
34
+ /** Returns a pointer for a given event */
35
+ export declare function getPointerForEvent(event: NostrEvent, relays?: string[]): DecodeResult;
@@ -1,6 +1,7 @@
1
1
  import { naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode, } from "nostr-tools/nip19";
2
- import { getPublicKey } from "nostr-tools";
2
+ import { getPublicKey, kinds } from "nostr-tools";
3
3
  import { safeRelayUrls } from "./relays.js";
4
+ import { getTagValue } from "./index.js";
4
5
  export function parseCoordinate(a, requireD = false, silent = true) {
5
6
  const parts = a.split(":");
6
7
  const kind = parts[0] && parseInt(parts[0]);
@@ -30,6 +31,7 @@ export function parseCoordinate(a, requireD = false, silent = true) {
30
31
  identifier: d,
31
32
  };
32
33
  }
34
+ /** Extra a pubkey from the result of nip19.decode */
33
35
  export function getPubkeyFromDecodeResult(result) {
34
36
  if (!result)
35
37
  return;
@@ -45,6 +47,7 @@ export function getPubkeyFromDecodeResult(result) {
45
47
  return undefined;
46
48
  }
47
49
  }
50
+ /** Encodes the result of nip19.decode */
48
51
  export function encodeDecodeResult(result) {
49
52
  switch (result.type) {
50
53
  case "naddr":
@@ -62,14 +65,19 @@ export function encodeDecodeResult(result) {
62
65
  }
63
66
  return "";
64
67
  }
68
+ /** @throws */
65
69
  export function getEventPointerFromTag(tag) {
66
70
  if (!tag[1])
67
71
  throw new Error("Missing event id in tag");
68
72
  let pointer = { id: tag[1] };
69
73
  if (tag[2])
70
74
  pointer.relays = safeRelayUrls([tag[2]]);
75
+ // get author from NIP-18 quote tags
76
+ if (tag[0] === "q" && tag[3] && tag[3].length === 64)
77
+ pointer.author = tag[3];
71
78
  return pointer;
72
79
  }
80
+ /** @throws */
73
81
  export function getAddressPointerFromTag(tag) {
74
82
  if (!tag[1])
75
83
  throw new Error("Missing coordinate in tag");
@@ -78,6 +86,7 @@ export function getAddressPointerFromTag(tag) {
78
86
  pointer.relays = safeRelayUrls([tag[2]]);
79
87
  return pointer;
80
88
  }
89
+ /** @throws */
81
90
  export function getProfilePointerFromTag(tag) {
82
91
  if (!tag[1])
83
92
  throw new Error("Missing pubkey in tag");
@@ -86,6 +95,7 @@ export function getProfilePointerFromTag(tag) {
86
95
  pointer.relays = safeRelayUrls([tag[2]]);
87
96
  return pointer;
88
97
  }
98
+ /** Parses "e", "a", "p", and "q" tags into a pointer */
89
99
  export function getPointerFromTag(tag) {
90
100
  try {
91
101
  switch (tag[0]) {
@@ -98,6 +108,9 @@ export function getPointerFromTag(tag) {
98
108
  };
99
109
  case "p":
100
110
  return { type: "nprofile", data: getProfilePointerFromTag(tag) };
111
+ // NIP-18 quote tags
112
+ case "q":
113
+ return { type: "nevent", data: getEventPointerFromTag(tag) };
101
114
  }
102
115
  }
103
116
  catch (error) { }
@@ -105,21 +118,52 @@ export function getPointerFromTag(tag) {
105
118
  }
106
119
  export function isAddressPointer(pointer) {
107
120
  return (typeof pointer !== "string" &&
108
- Object.hasOwn(pointer, "identifier") &&
109
- Object.hasOwn(pointer, "pubkey") &&
110
- Object.hasOwn(pointer, "kind"));
121
+ Reflect.has(pointer, "identifier") &&
122
+ Reflect.has(pointer, "pubkey") &&
123
+ Reflect.has(pointer, "kind"));
111
124
  }
112
125
  export function isEventPointer(pointer) {
113
- return typeof pointer !== "string" && Object.hasOwn(pointer, "id");
126
+ return typeof pointer !== "string" && Reflect.has(pointer, "id");
114
127
  }
128
+ /** Returns the coordinate string for an AddressPointer */
115
129
  export function getCoordinateFromAddressPointer(pointer) {
116
130
  return `${pointer.kind}:${pointer.pubkey}:${pointer.identifier}`;
117
131
  }
132
+ /** Returns a tag for an address pointer */
118
133
  export function getATagFromAddressPointer(pointer) {
119
134
  const relay = pointer.relays?.[0];
120
135
  const coordinate = getCoordinateFromAddressPointer(pointer);
121
136
  return relay ? ["a", coordinate, relay] : ["a", coordinate];
122
137
  }
138
+ /** Returns a tag for an event pointer */
123
139
  export function getETagFromEventPointer(pointer) {
124
140
  return pointer.relays?.length ? ["e", pointer.id, pointer.relays[0]] : ["e", pointer.id];
125
141
  }
142
+ /** Returns a pointer for a given event */
143
+ export function getPointerForEvent(event, relays) {
144
+ if (kinds.isParameterizedReplaceableKind(event.kind)) {
145
+ const d = getTagValue(event, "d");
146
+ if (!d)
147
+ throw new Error("Event missing identifier");
148
+ return {
149
+ type: "naddr",
150
+ data: {
151
+ identifier: d,
152
+ kind: event.kind,
153
+ pubkey: event.pubkey,
154
+ relays,
155
+ },
156
+ };
157
+ }
158
+ else {
159
+ return {
160
+ type: "nevent",
161
+ data: {
162
+ id: event.id,
163
+ kind: event.kind,
164
+ author: event.pubkey,
165
+ relays,
166
+ },
167
+ };
168
+ }
169
+ }
@@ -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[]];
@@ -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
  }
@@ -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
- export declare function isVisualMediaURL(url: string | URL): boolean;
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;
@@ -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
- export function isVisualMediaURL(url) {
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);
@@ -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;