applesauce-core 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/dist/event-store/database.d.ts +17 -14
  3. package/dist/event-store/database.js +50 -33
  4. package/dist/event-store/event-store.d.ts +37 -14
  5. package/dist/event-store/event-store.js +249 -96
  6. package/dist/helpers/bolt11.d.ts +9 -0
  7. package/dist/helpers/bolt11.js +15 -0
  8. package/dist/helpers/cache.js +9 -9
  9. package/dist/helpers/comment.d.ts +48 -0
  10. package/dist/helpers/comment.js +116 -0
  11. package/dist/helpers/content.d.ts +3 -0
  12. package/dist/helpers/content.js +8 -0
  13. package/dist/helpers/delete.d.ts +3 -0
  14. package/dist/helpers/delete.js +7 -0
  15. package/dist/helpers/emoji.d.ts +10 -1
  16. package/dist/helpers/emoji.js +12 -0
  17. package/dist/helpers/event.d.ts +9 -1
  18. package/dist/helpers/event.js +25 -1
  19. package/dist/helpers/external-id.d.ts +29 -0
  20. package/dist/helpers/external-id.js +20 -0
  21. package/dist/helpers/filter.d.ts +0 -2
  22. package/dist/helpers/filter.js +3 -7
  23. package/dist/helpers/hidden-tags.d.ts +48 -0
  24. package/dist/helpers/hidden-tags.js +108 -0
  25. package/dist/helpers/hidden-tags.test.d.ts +1 -0
  26. package/dist/helpers/hidden-tags.test.js +28 -0
  27. package/dist/helpers/index.d.ts +17 -7
  28. package/dist/helpers/index.js +17 -7
  29. package/dist/helpers/json.d.ts +1 -0
  30. package/dist/helpers/json.js +1 -0
  31. package/dist/helpers/lnurl.d.ts +4 -0
  32. package/dist/helpers/lnurl.js +40 -0
  33. package/dist/helpers/mailboxes.d.ts +0 -6
  34. package/dist/helpers/mailboxes.js +7 -8
  35. package/dist/helpers/mailboxes.test.js +13 -12
  36. package/dist/helpers/media-attachment.d.ts +33 -0
  37. package/dist/helpers/media-attachment.js +60 -0
  38. package/dist/helpers/pointers.d.ts +39 -6
  39. package/dist/helpers/pointers.js +102 -20
  40. package/dist/helpers/profile.d.ts +2 -7
  41. package/dist/helpers/profile.js +26 -23
  42. package/dist/helpers/string.d.ts +6 -0
  43. package/dist/helpers/string.js +2 -0
  44. package/dist/helpers/tags.d.ts +6 -0
  45. package/dist/helpers/tags.js +6 -0
  46. package/dist/helpers/threading.d.ts +10 -10
  47. package/dist/helpers/threading.js +52 -19
  48. package/dist/helpers/threading.test.d.ts +1 -0
  49. package/dist/helpers/threading.test.js +41 -0
  50. package/dist/helpers/url.d.ts +4 -1
  51. package/dist/helpers/url.js +4 -3
  52. package/dist/helpers/zap.d.ts +39 -0
  53. package/dist/helpers/zap.js +95 -0
  54. package/dist/observable/{getValue.d.ts → get-value.d.ts} +1 -0
  55. package/dist/observable/{getValue.js → get-value.js} +3 -0
  56. package/dist/observable/index.d.ts +1 -1
  57. package/dist/observable/index.js +1 -1
  58. package/dist/promise/deferred.d.ts +1 -0
  59. package/dist/promise/deferred.js +1 -0
  60. package/dist/queries/comments.d.ts +4 -0
  61. package/dist/queries/comments.js +14 -0
  62. package/dist/queries/index.d.ts +4 -2
  63. package/dist/queries/index.js +4 -2
  64. package/dist/queries/mailboxes.d.ts +1 -0
  65. package/dist/queries/mailboxes.js +1 -0
  66. package/dist/queries/profile.d.ts +1 -0
  67. package/dist/queries/profile.js +4 -3
  68. package/dist/queries/reactions.d.ts +1 -1
  69. package/dist/queries/reactions.js +1 -1
  70. package/dist/queries/simple.d.ts +3 -3
  71. package/dist/queries/simple.js +13 -13
  72. package/dist/queries/thread.d.ts +2 -0
  73. package/dist/queries/thread.js +29 -3
  74. package/dist/queries/zaps.d.ts +5 -0
  75. package/dist/queries/zaps.js +21 -0
  76. package/dist/query-store/index.d.ts +22 -12
  77. package/dist/query-store/index.js +36 -30
  78. package/package.json +14 -16
@@ -1,11 +1,12 @@
1
1
  import { safeRelayUrl } from "./relays.js";
2
+ import { getOrComputeCachedValue } from "./cache.js";
2
3
  export const MailboxesInboxesSymbol = Symbol.for("mailboxes-inboxes");
3
4
  export const MailboxesOutboxesSymbol = Symbol.for("mailboxes-outboxes");
4
5
  /**
5
6
  * Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol
6
7
  */
7
8
  export function getInboxes(event) {
8
- if (!event[MailboxesInboxesSymbol]) {
9
+ return getOrComputeCachedValue(event, MailboxesInboxesSymbol, () => {
9
10
  const inboxes = [];
10
11
  for (const tag of event.tags) {
11
12
  if (tag[0] === "r" && tag[1] && (tag[2] === "read" || tag[2] === undefined)) {
@@ -14,15 +15,14 @@ export function getInboxes(event) {
14
15
  inboxes.push(url);
15
16
  }
16
17
  }
17
- event[MailboxesInboxesSymbol] = inboxes;
18
- }
19
- return event[MailboxesInboxesSymbol];
18
+ return inboxes;
19
+ });
20
20
  }
21
21
  /**
22
22
  * Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol
23
23
  */
24
24
  export function getOutboxes(event) {
25
- if (!event[MailboxesOutboxesSymbol]) {
25
+ return getOrComputeCachedValue(event, MailboxesOutboxesSymbol, () => {
26
26
  const outboxes = [];
27
27
  for (const tag of event.tags) {
28
28
  if (tag[0] === "r" && tag[1] && (tag[2] === "write" || tag[2] === undefined)) {
@@ -31,7 +31,6 @@ export function getOutboxes(event) {
31
31
  outboxes.push(url);
32
32
  }
33
33
  }
34
- event[MailboxesOutboxesSymbol] = outboxes;
35
- }
36
- return event[MailboxesOutboxesSymbol];
34
+ return outboxes;
35
+ });
37
36
  }
@@ -1,3 +1,4 @@
1
+ import { describe, test, expect } from "vitest";
1
2
  import { getInboxes, getOutboxes } from "./mailboxes.js";
2
3
  const emptyEvent = {
3
4
  kind: 10002,
@@ -14,33 +15,33 @@ describe("Mailboxes", () => {
14
15
  expect(Array.from(getInboxes({
15
16
  ...emptyEvent,
16
17
  tags: [["r", "wss://inbox.com"]],
17
- }))).toIncludeAllMembers(["wss://inbox.com/"]);
18
+ }))).toEqual(expect.arrayContaining(["wss://inbox.com/"]));
18
19
  });
19
20
  test("should remove bad urls", () => {
20
21
  expect(Array.from(getInboxes({
21
22
  ...emptyEvent,
22
23
  tags: [["r", "bad://inbox.com"]],
23
- }))).toBeArrayOfSize(0);
24
+ }))).toHaveLength(0);
24
25
  expect(Array.from(getInboxes({
25
26
  ...emptyEvent,
26
27
  tags: [["r", "something that is not a url"]],
27
- }))).toBeArrayOfSize(0);
28
+ }))).toHaveLength(0);
28
29
  expect(Array.from(getInboxes({
29
30
  ...emptyEvent,
30
31
  tags: [["r", "wss://inbox.com,wss://inbox.org"]],
31
- }))).toBeArrayOfSize(0);
32
+ }))).toHaveLength(0);
32
33
  });
33
34
  test("without marker", () => {
34
35
  expect(Array.from(getInboxes({
35
36
  ...emptyEvent,
36
37
  tags: [["r", "wss://inbox.com/"]],
37
- }))).toIncludeAllMembers(["wss://inbox.com/"]);
38
+ }))).toEqual(expect.arrayContaining(["wss://inbox.com/"]));
38
39
  });
39
40
  test("with marker", () => {
40
41
  expect(Array.from(getInboxes({
41
42
  ...emptyEvent,
42
43
  tags: [["r", "wss://inbox.com/", "read"]],
43
- }))).toIncludeAllMembers(["wss://inbox.com/"]);
44
+ }))).toEqual(expect.arrayContaining(["wss://inbox.com/"]));
44
45
  });
45
46
  });
46
47
  describe("getOutboxes", () => {
@@ -48,33 +49,33 @@ describe("Mailboxes", () => {
48
49
  expect(Array.from(getOutboxes({
49
50
  ...emptyEvent,
50
51
  tags: [["r", "wss://outbox.com"]],
51
- }))).toIncludeAllMembers(["wss://outbox.com/"]);
52
+ }))).toEqual(expect.arrayContaining(["wss://outbox.com/"]));
52
53
  });
53
54
  test("should remove bad urls", () => {
54
55
  expect(Array.from(getOutboxes({
55
56
  ...emptyEvent,
56
57
  tags: [["r", "bad://inbox.com"]],
57
- }))).toBeArrayOfSize(0);
58
+ }))).toHaveLength(0);
58
59
  expect(Array.from(getOutboxes({
59
60
  ...emptyEvent,
60
61
  tags: [["r", "something that is not a url"]],
61
- }))).toBeArrayOfSize(0);
62
+ }))).toHaveLength(0);
62
63
  expect(Array.from(getOutboxes({
63
64
  ...emptyEvent,
64
65
  tags: [["r", "wss://outbox.com,wss://inbox.org"]],
65
- }))).toBeArrayOfSize(0);
66
+ }))).toHaveLength(0);
66
67
  });
67
68
  test("without marker", () => {
68
69
  expect(Array.from(getOutboxes({
69
70
  ...emptyEvent,
70
71
  tags: [["r", "wss://outbox.com/"]],
71
- }))).toIncludeAllMembers(["wss://outbox.com/"]);
72
+ }))).toEqual(expect.arrayContaining(["wss://outbox.com/"]));
72
73
  });
73
74
  test("with marker", () => {
74
75
  expect(Array.from(getOutboxes({
75
76
  ...emptyEvent,
76
77
  tags: [["r", "wss://outbox.com/", "write"]],
77
- }))).toIncludeAllMembers(["wss://outbox.com/"]);
78
+ }))).toEqual(expect.arrayContaining(["wss://outbox.com/"]));
78
79
  });
79
80
  });
80
81
  });
@@ -0,0 +1,33 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ export type MediaAttachment = {
3
+ /** URL of the file */
4
+ url: string;
5
+ /** mime type */
6
+ type?: string;
7
+ /** sha256 hash of the file */
8
+ sha256?: string;
9
+ /** size of the file in bytes */
10
+ size?: number;
11
+ /** size of file in pixels in the form <width>x<height> */
12
+ dimensions?: string;
13
+ /** magnet */
14
+ magnet?: string;
15
+ /** torrent infohash */
16
+ infohash?: string;
17
+ /** URL to a thumbnail */
18
+ thumb?: string;
19
+ /** URL to a preview image with the same dimensions */
20
+ image?: string;
21
+ /** summary */
22
+ summary?: string;
23
+ /** description for accessability */
24
+ alt?: string;
25
+ };
26
+ /**
27
+ * Parses a imeta tag into a {@link MediaAttachment}
28
+ * @throws
29
+ */
30
+ export declare function parseMediaAttachmentTag(tag: string[]): MediaAttachment;
31
+ export declare const MediaAttachmentsSymbol: unique symbol;
32
+ /** Gets all the media attachments on an event */
33
+ export declare function getMediaAttachments(event: NostrEvent): MediaAttachment[];
@@ -0,0 +1,60 @@
1
+ import { getOrComputeCachedValue } from "./cache.js";
2
+ /**
3
+ * Parses a imeta tag into a {@link MediaAttachment}
4
+ * @throws
5
+ */
6
+ export function parseMediaAttachmentTag(tag) {
7
+ const parts = tag.slice(1);
8
+ const fields = {};
9
+ for (const part of parts) {
10
+ const match = part.match(/^(.+?)\s(.+)$/);
11
+ if (match) {
12
+ const [_, name, value] = match;
13
+ fields[name] = value;
14
+ }
15
+ }
16
+ if (!fields.url)
17
+ throw new Error("Missing required url in attachment");
18
+ const attachment = { url: fields.url };
19
+ // parse size
20
+ if (fields.size)
21
+ attachment.size = parseInt(fields.size);
22
+ // copy optional fields
23
+ if (fields.m)
24
+ attachment.type = fields.m;
25
+ if (fields.x)
26
+ attachment.sha256 = fields.x;
27
+ if (fields.dim)
28
+ attachment.dimensions = fields.dim;
29
+ if (fields.magnet)
30
+ attachment.magnet = fields.magnet;
31
+ if (fields.i)
32
+ attachment.infohash = fields.i;
33
+ if (fields.thumb)
34
+ attachment.thumb = fields.thumb;
35
+ if (fields.image)
36
+ attachment.image = fields.image;
37
+ if (fields.summary)
38
+ attachment.summary = fields.summary;
39
+ if (fields.alt)
40
+ attachment.alt = fields.alt;
41
+ return attachment;
42
+ }
43
+ export const MediaAttachmentsSymbol = Symbol.for("media-attachments");
44
+ /** Gets all the media attachments on an event */
45
+ export function getMediaAttachments(event) {
46
+ return getOrComputeCachedValue(event, MediaAttachmentsSymbol, () => {
47
+ return event.tags
48
+ .filter((t) => t[0] === "imeta")
49
+ .map((tag) => {
50
+ try {
51
+ return parseMediaAttachmentTag(tag);
52
+ }
53
+ catch (error) {
54
+ // ignore invalid attachments
55
+ return undefined;
56
+ }
57
+ })
58
+ .filter((a) => !!a);
59
+ });
60
+ }
@@ -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,45 @@ 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;
13
- export declare function encodeDecodeResult(result: DecodeResult): "" | `nsec1${string}` | `npub1${string}` | `note1${string}` | `nprofile1${string}` | `nevent1${string}` | `naddr1${string}` | `nrelay1${string}`;
14
- export declare function getEventPointerFromTag(tag: string[]): EventPointer;
15
- export declare function getAddressPointerFromTag(tag: string[]): AddressPointer;
16
- export declare function getProfilePointerFromTag(tag: string[]): ProfilePointer;
16
+ /** Encodes the result of nip19.decode */
17
+ export declare function encodeDecodeResult(result: DecodeResult): "" | `nprofile1${string}` | `nevent1${string}` | `naddr1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
18
+ /**
19
+ * Gets an EventPointer form a common "e" tag
20
+ * @throws
21
+ */
22
+ export declare function getEventPointerFromETag(tag: string[]): EventPointer;
23
+ /**
24
+ * Gets an EventPointer form a "q" tag
25
+ * @throws
26
+ */
27
+ export declare function getEventPointerFromQTag(tag: string[]): EventPointer;
28
+ /**
29
+ * Get an AddressPointer from an "a" tag
30
+ * @throws
31
+ */
32
+ export declare function getAddressPointerFromATag(tag: string[]): AddressPointer;
33
+ /**
34
+ * Gets a ProfilePointer from a "p" tag
35
+ * @throws
36
+ */
37
+ export declare function getProfilePointerFromPTag(tag: string[]): ProfilePointer;
38
+ /** Parses "e", "a", "p", and "q" tags into a pointer */
17
39
  export declare function getPointerFromTag(tag: string[]): DecodeResult | null;
18
40
  export declare function isAddressPointer(pointer: DecodeResult["data"]): pointer is AddressPointer;
19
41
  export declare function isEventPointer(pointer: DecodeResult["data"]): pointer is EventPointer;
42
+ /** Returns the coordinate string for an AddressPointer */
20
43
  export declare function getCoordinateFromAddressPointer(pointer: AddressPointer): string;
21
- export declare function getATagFromAddressPointer(pointer: AddressPointer): ["a", ...string[]];
22
- export declare function getETagFromEventPointer(pointer: EventPointer): ["e", ...string[]];
44
+ /**
45
+ * Returns an AddressPointer for a replaceable event
46
+ * @throws
47
+ */
48
+ export declare function getAddressPointerForEvent(event: NostrEvent, relays?: string[]): AddressPointer;
49
+ /**
50
+ * Returns an EventPointer for an event
51
+ * @throws
52
+ */
53
+ export declare function getEventPointerForEvent(event: NostrEvent, relays?: string[]): EventPointer;
54
+ /** Returns a pointer for a given event */
55
+ export declare function getPointerForEvent(event: NostrEvent, relays?: string[]): DecodeResult;
@@ -1,6 +1,8 @@
1
- import { naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nrelayEncode, nsecEncode, } from "nostr-tools/nip19";
2
- import { getPublicKey } from "nostr-tools";
1
+ import { naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode, } from "nostr-tools/nip19";
2
+ import { getPublicKey, kinds } from "nostr-tools";
3
3
  import { safeRelayUrls } from "./relays.js";
4
+ import { getTagValue } from "./index.js";
5
+ import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
4
6
  export function parseCoordinate(a, requireD = false, silent = true) {
5
7
  const parts = a.split(":");
6
8
  const kind = parts[0] && parseInt(parts[0]);
@@ -30,6 +32,7 @@ export function parseCoordinate(a, requireD = false, silent = true) {
30
32
  identifier: d,
31
33
  };
32
34
  }
35
+ /** Extra a pubkey from the result of nip19.decode */
33
36
  export function getPubkeyFromDecodeResult(result) {
34
37
  if (!result)
35
38
  return;
@@ -45,6 +48,7 @@ export function getPubkeyFromDecodeResult(result) {
45
48
  return undefined;
46
49
  }
47
50
  }
51
+ /** Encodes the result of nip19.decode */
48
52
  export function encodeDecodeResult(result) {
49
53
  switch (result.type) {
50
54
  case "naddr":
@@ -53,8 +57,6 @@ export function encodeDecodeResult(result) {
53
57
  return nprofileEncode(result.data);
54
58
  case "nevent":
55
59
  return neventEncode(result.data);
56
- case "nrelay":
57
- return nrelayEncode(result.data);
58
60
  case "nsec":
59
61
  return nsecEncode(result.data);
60
62
  case "npub":
@@ -64,7 +66,11 @@ export function encodeDecodeResult(result) {
64
66
  }
65
67
  return "";
66
68
  }
67
- export function getEventPointerFromTag(tag) {
69
+ /**
70
+ * Gets an EventPointer form a common "e" tag
71
+ * @throws
72
+ */
73
+ export function getEventPointerFromETag(tag) {
68
74
  if (!tag[1])
69
75
  throw new Error("Missing event id in tag");
70
76
  let pointer = { id: tag[1] };
@@ -72,7 +78,25 @@ export function getEventPointerFromTag(tag) {
72
78
  pointer.relays = safeRelayUrls([tag[2]]);
73
79
  return pointer;
74
80
  }
75
- export function getAddressPointerFromTag(tag) {
81
+ /**
82
+ * Gets an EventPointer form a "q" tag
83
+ * @throws
84
+ */
85
+ export function getEventPointerFromQTag(tag) {
86
+ if (!tag[1])
87
+ throw new Error("Missing event id in tag");
88
+ let pointer = { id: tag[1] };
89
+ if (tag[2])
90
+ pointer.relays = safeRelayUrls([tag[2]]);
91
+ if (tag[3] && tag[3].length === 64)
92
+ pointer.author = tag[3];
93
+ return pointer;
94
+ }
95
+ /**
96
+ * Get an AddressPointer from an "a" tag
97
+ * @throws
98
+ */
99
+ export function getAddressPointerFromATag(tag) {
76
100
  if (!tag[1])
77
101
  throw new Error("Missing coordinate in tag");
78
102
  const pointer = parseCoordinate(tag[1], true, false);
@@ -80,7 +104,11 @@ export function getAddressPointerFromTag(tag) {
80
104
  pointer.relays = safeRelayUrls([tag[2]]);
81
105
  return pointer;
82
106
  }
83
- export function getProfilePointerFromTag(tag) {
107
+ /**
108
+ * Gets a ProfilePointer from a "p" tag
109
+ * @throws
110
+ */
111
+ export function getProfilePointerFromPTag(tag) {
84
112
  if (!tag[1])
85
113
  throw new Error("Missing pubkey in tag");
86
114
  const pointer = { pubkey: tag[1] };
@@ -88,18 +116,22 @@ export function getProfilePointerFromTag(tag) {
88
116
  pointer.relays = safeRelayUrls([tag[2]]);
89
117
  return pointer;
90
118
  }
119
+ /** Parses "e", "a", "p", and "q" tags into a pointer */
91
120
  export function getPointerFromTag(tag) {
92
121
  try {
93
122
  switch (tag[0]) {
94
123
  case "e":
95
- return { type: "nevent", data: getEventPointerFromTag(tag) };
124
+ return { type: "nevent", data: getEventPointerFromETag(tag) };
96
125
  case "a":
97
126
  return {
98
127
  type: "naddr",
99
- data: getAddressPointerFromTag(tag),
128
+ data: getAddressPointerFromATag(tag),
100
129
  };
101
130
  case "p":
102
- return { type: "nprofile", data: getProfilePointerFromTag(tag) };
131
+ return { type: "nprofile", data: getProfilePointerFromPTag(tag) };
132
+ // NIP-18 quote tags
133
+ case "q":
134
+ return { type: "nevent", data: getEventPointerFromETag(tag) };
103
135
  }
104
136
  }
105
137
  catch (error) { }
@@ -107,21 +139,71 @@ export function getPointerFromTag(tag) {
107
139
  }
108
140
  export function isAddressPointer(pointer) {
109
141
  return (typeof pointer !== "string" &&
110
- Object.hasOwn(pointer, "identifier") &&
111
- Object.hasOwn(pointer, "pubkey") &&
112
- Object.hasOwn(pointer, "kind"));
142
+ Reflect.has(pointer, "identifier") &&
143
+ Reflect.has(pointer, "pubkey") &&
144
+ Reflect.has(pointer, "kind"));
113
145
  }
114
146
  export function isEventPointer(pointer) {
115
- return typeof pointer !== "string" && Object.hasOwn(pointer, "id");
147
+ return typeof pointer !== "string" && Reflect.has(pointer, "id");
116
148
  }
149
+ /** Returns the coordinate string for an AddressPointer */
117
150
  export function getCoordinateFromAddressPointer(pointer) {
118
151
  return `${pointer.kind}:${pointer.pubkey}:${pointer.identifier}`;
119
152
  }
120
- export function getATagFromAddressPointer(pointer) {
121
- const relay = pointer.relays?.[0];
122
- const coordinate = getCoordinateFromAddressPointer(pointer);
123
- return relay ? ["a", coordinate, relay] : ["a", coordinate];
153
+ /**
154
+ * Returns an AddressPointer for a replaceable event
155
+ * @throws
156
+ */
157
+ export function getAddressPointerForEvent(event, relays) {
158
+ if (!isParameterizedReplaceableKind(event.kind))
159
+ throw new Error("Cant get AddressPointer for non-replaceable event");
160
+ const d = getTagValue(event, "d");
161
+ if (!d)
162
+ throw new Error("Event missing identifier");
163
+ return {
164
+ identifier: d,
165
+ kind: event.kind,
166
+ pubkey: event.pubkey,
167
+ relays,
168
+ };
124
169
  }
125
- export function getETagFromEventPointer(pointer) {
126
- return pointer.relays?.length ? ["e", pointer.id, pointer.relays[0]] : ["e", pointer.id];
170
+ /**
171
+ * Returns an EventPointer for an event
172
+ * @throws
173
+ */
174
+ export function getEventPointerForEvent(event, relays) {
175
+ return {
176
+ id: event.id,
177
+ kind: event.kind,
178
+ author: event.pubkey,
179
+ relays,
180
+ };
181
+ }
182
+ /** Returns a pointer for a given event */
183
+ export function getPointerForEvent(event, relays) {
184
+ if (kinds.isParameterizedReplaceableKind(event.kind)) {
185
+ const d = getTagValue(event, "d");
186
+ if (!d)
187
+ throw new Error("Event missing identifier");
188
+ return {
189
+ type: "naddr",
190
+ data: {
191
+ identifier: d,
192
+ kind: event.kind,
193
+ pubkey: event.pubkey,
194
+ relays,
195
+ },
196
+ };
197
+ }
198
+ else {
199
+ return {
200
+ type: "nevent",
201
+ data: {
202
+ id: event.id,
203
+ kind: event.kind,
204
+ author: event.pubkey,
205
+ relays,
206
+ },
207
+ };
208
+ }
127
209
  }
@@ -1,10 +1,5 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
2
  export declare const ProfileContentSymbol: unique symbol;
3
- declare module "nostr-tools" {
4
- interface Event {
5
- [ProfileContentSymbol]?: ProfileContent | Error;
6
- }
7
- }
8
3
  export type ProfileContent = {
9
4
  name?: string;
10
5
  display_name?: string;
@@ -21,5 +16,5 @@ export type ProfileContent = {
21
16
  };
22
17
  /** Returns the parsed profile content for a kind 0 event */
23
18
  export declare function getProfileContent(event: NostrEvent): ProfileContent;
24
- export declare function getProfileContent(event: NostrEvent, quite: false): ProfileContent;
25
- export declare function getProfileContent(event: NostrEvent, quite: true): ProfileContent | Error;
19
+ /** Checks if the content of the kind 0 event is valid JSON */
20
+ export declare function isValidProfile(profile?: NostrEvent): boolean;
@@ -1,28 +1,31 @@
1
+ import { kinds } from "nostr-tools";
2
+ import { getOrComputeCachedValue } from "./cache.js";
1
3
  export const ProfileContentSymbol = Symbol.for("profile-content");
2
- export function getProfileContent(event, quite = false) {
3
- let cached = event[ProfileContentSymbol];
4
- if (!cached) {
5
- try {
6
- const profile = JSON.parse(event.content);
7
- // ensure nip05 is a string
8
- if (profile.nip05 && typeof profile.nip05 !== "string")
9
- profile.nip05 = String(profile.nip05);
10
- cached = event[ProfileContentSymbol] = profile;
4
+ /** Returns the parsed profile content for a kind 0 event */
5
+ export function getProfileContent(event) {
6
+ return getOrComputeCachedValue(event, ProfileContentSymbol, () => {
7
+ const profile = JSON.parse(event.content);
8
+ // ensure nip05 is a string
9
+ if (profile.nip05 && typeof profile.nip05 !== "string")
10
+ profile.nip05 = String(profile.nip05);
11
+ // add missing protocol to website
12
+ if (profile.website && profile.website?.length > 0 && profile.website?.startsWith("http") === false) {
13
+ profile.website = "https://" + profile.website;
11
14
  }
12
- catch (e) {
13
- if (e instanceof Error)
14
- cached = event[ProfileContentSymbol] = e;
15
- }
16
- }
17
- if (cached === undefined) {
18
- throw new Error("Failed to parse profile");
15
+ return profile;
16
+ });
17
+ }
18
+ /** Checks if the content of the kind 0 event is valid JSON */
19
+ export function isValidProfile(profile) {
20
+ if (!profile)
21
+ return false;
22
+ if (profile.kind !== kinds.Metadata)
23
+ return false;
24
+ try {
25
+ getProfileContent(profile);
26
+ return true;
19
27
  }
20
- else if (cached instanceof Error) {
21
- if (!quite)
22
- throw cached;
23
- else
24
- return cached;
28
+ catch (error) {
29
+ return false;
25
30
  }
26
- else
27
- return cached;
28
31
  }
@@ -1,4 +1,10 @@
1
+ /** Tests if a string is hex */
1
2
  export declare function isHex(str?: string): boolean;
3
+ /** Tests if a string is a 64 length hex string */
2
4
  export declare function isHexKey(key?: string): boolean;
5
+ /**
6
+ * Remove invisible characters from a string
7
+ * @see read more https://www.regular-expressions.info/unicode.html#category
8
+ */
3
9
  export declare function stripInvisibleChar(str: string): string;
4
10
  export declare function stripInvisibleChar(str?: string | undefined): string | undefined;
@@ -1,8 +1,10 @@
1
+ /** Tests if a string is hex */
1
2
  export function isHex(str) {
2
3
  if (str?.match(/^[0-9a-f]+$/i))
3
4
  return true;
4
5
  return false;
5
6
  }
7
+ /** Tests if a string is a 64 length hex string */
6
8
  export function isHexKey(key) {
7
9
  if (key?.toLowerCase()?.match(/^[0-9a-f]{64}$/))
8
10
  return true;
@@ -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
  }
@@ -1,4 +1,4 @@
1
- import { NostrEvent } from "nostr-tools";
1
+ import { EventTemplate, NostrEvent } from "nostr-tools";
2
2
  import { AddressPointer, EventPointer } from "nostr-tools/nip19";
3
3
  export type ThreadReferences = {
4
4
  root?: {
@@ -23,13 +23,13 @@ export type ThreadReferences = {
23
23
  };
24
24
  };
25
25
  export declare const Nip10ThreadRefsSymbol: unique symbol;
26
- declare module "nostr-tools" {
27
- interface Event {
28
- [Nip10ThreadRefsSymbol]?: ThreadReferences;
29
- }
30
- }
26
+ /**
27
+ * Gets an EventPointer form a NIP-10 threading "e" tag
28
+ * @throws
29
+ */
30
+ export declare function getEventPointerFromThreadTag(tag: string[]): EventPointer;
31
31
  /** Parses NIP-10 tags and handles legacy behavior */
32
- export declare function interpretThreadTags(event: NostrEvent): {
32
+ export declare function interpretThreadTags(tags: string[][]): {
33
33
  root?: {
34
34
  e: string[];
35
35
  a: undefined;
@@ -39,7 +39,7 @@ export declare function interpretThreadTags(event: NostrEvent): {
39
39
  } | {
40
40
  e: string[];
41
41
  a: string[];
42
- } | undefined;
42
+ };
43
43
  reply?: {
44
44
  e: string[];
45
45
  a: undefined;
@@ -49,7 +49,7 @@ export declare function interpretThreadTags(event: NostrEvent): {
49
49
  } | {
50
50
  e: string[];
51
51
  a: string[];
52
- } | undefined;
52
+ };
53
53
  };
54
54
  /** Returns the parsed NIP-10 tags for an event */
55
- export declare function getNip10References(event: NostrEvent): ThreadReferences;
55
+ export declare function getNip10References(event: NostrEvent | EventTemplate): ThreadReferences;