applesauce-core 5.1.0 → 6.0.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 (80) hide show
  1. package/dist/casts/cast.d.ts +31 -0
  2. package/dist/casts/cast.js +67 -0
  3. package/dist/casts/index.d.ts +3 -0
  4. package/dist/casts/index.js +3 -0
  5. package/dist/casts/pubkey.d.ts +27 -0
  6. package/dist/casts/pubkey.js +49 -0
  7. package/dist/casts/user.d.ts +19 -0
  8. package/dist/casts/user.js +25 -0
  9. package/dist/factories/delete.d.ts +18 -0
  10. package/dist/factories/delete.js +23 -0
  11. package/dist/factories/event.d.ts +61 -0
  12. package/dist/factories/event.js +164 -0
  13. package/dist/factories/index.d.ts +5 -0
  14. package/dist/factories/index.js +5 -0
  15. package/dist/factories/mailboxes.d.ts +33 -0
  16. package/dist/factories/mailboxes.js +57 -0
  17. package/dist/factories/profile.d.ts +46 -0
  18. package/dist/factories/profile.js +80 -0
  19. package/dist/factories/types.d.ts +56 -0
  20. package/dist/helpers/event.d.ts +11 -2
  21. package/dist/helpers/event.js +2 -1
  22. package/dist/helpers/mailboxes.d.ts +5 -1
  23. package/dist/helpers/mailboxes.js +5 -0
  24. package/dist/helpers/pipeline.d.ts +14 -1
  25. package/dist/helpers/pipeline.js +17 -2
  26. package/dist/helpers/pointers.d.ts +25 -21
  27. package/dist/helpers/pointers.js +33 -18
  28. package/dist/helpers/profile.d.ts +2 -2
  29. package/dist/helpers/regexp.d.ts +2 -0
  30. package/dist/helpers/regexp.js +8 -2
  31. package/dist/helpers/relays.d.ts +3 -1
  32. package/dist/helpers/relays.js +8 -10
  33. package/dist/helpers/url.d.ts +1 -4
  34. package/dist/helpers/url.js +1 -4
  35. package/dist/index.d.ts +3 -1
  36. package/dist/index.js +4 -1
  37. package/dist/observable/catch-error-inline.d.ts +3 -0
  38. package/dist/observable/catch-error-inline.js +5 -0
  39. package/dist/observable/chainable.d.ts +36 -0
  40. package/dist/observable/chainable.js +72 -0
  41. package/dist/observable/combine-latest-by-index.d.ts +10 -0
  42. package/dist/observable/combine-latest-by-index.js +121 -0
  43. package/dist/observable/combine-latest-by-key.d.ts +10 -0
  44. package/dist/observable/combine-latest-by-key.js +136 -0
  45. package/dist/observable/combine-latest-by-value.d.ts +10 -0
  46. package/dist/observable/combine-latest-by-value.js +117 -0
  47. package/dist/observable/combine-latest-by.d.ts +16 -0
  48. package/dist/observable/combine-latest-by.js +12 -0
  49. package/dist/observable/index.d.ts +10 -4
  50. package/dist/observable/index.js +10 -4
  51. package/dist/observable/timeout-with-ignore.d.ts +24 -0
  52. package/dist/observable/timeout-with-ignore.js +33 -0
  53. package/dist/operations/client.d.ts +1 -1
  54. package/dist/operations/client.js +2 -2
  55. package/dist/operations/content.d.ts +5 -2
  56. package/dist/operations/content.js +13 -9
  57. package/dist/operations/delete.d.ts +1 -1
  58. package/dist/operations/encrypted-content.d.ts +9 -3
  59. package/dist/operations/encrypted-content.js +9 -3
  60. package/dist/operations/event.d.ts +6 -4
  61. package/dist/operations/event.js +20 -12
  62. package/dist/operations/hidden-content.d.ts +8 -3
  63. package/dist/operations/hidden-content.js +11 -6
  64. package/dist/operations/mailboxes.d.ts +5 -1
  65. package/dist/operations/mailboxes.js +76 -0
  66. package/dist/operations/profile.d.ts +1 -1
  67. package/dist/operations/tag/common.d.ts +22 -7
  68. package/dist/operations/tag/common.js +33 -18
  69. package/dist/operations/tag/relay.d.ts +1 -1
  70. package/dist/operations/tags.d.ts +10 -4
  71. package/dist/operations/tags.js +19 -13
  72. package/package.json +20 -5
  73. package/dist/event-factory/event-factory.d.ts +0 -57
  74. package/dist/event-factory/event-factory.js +0 -94
  75. package/dist/event-factory/index.d.ts +0 -3
  76. package/dist/event-factory/index.js +0 -3
  77. package/dist/event-factory/methods.d.ts +0 -17
  78. package/dist/event-factory/methods.js +0 -44
  79. package/dist/event-factory/types.d.ts +0 -76
  80. /package/dist/{event-factory → factories}/types.js +0 -0
@@ -0,0 +1,80 @@
1
+ import { isKind } from "nostr-tools/kinds";
2
+ import { kinds } from "../helpers/event.js";
3
+ import { setProfile, updateProfile } from "../operations/profile.js";
4
+ import { blankEventTemplate, EventFactory, toEventTemplate } from "./event.js";
5
+ /** A factory class for building kind 0 profile/metadata events */
6
+ export class ProfileFactory extends EventFactory {
7
+ /**
8
+ * Creates a new profile factory
9
+ * @returns A new profile factory
10
+ */
11
+ static create() {
12
+ return new ProfileFactory((res) => res(blankEventTemplate(kinds.Metadata)));
13
+ }
14
+ /**
15
+ * Creates a new profile factory from an existing metadata event with validation
16
+ * @param event - The existing metadata event
17
+ * @returns A new profile factory
18
+ */
19
+ static modify(event) {
20
+ if (!isKind(event, kinds.Metadata))
21
+ throw new Error("Event is not a profile event");
22
+ return new ProfileFactory((res) => res(toEventTemplate(event)));
23
+ }
24
+ /** Sets the entire profile content, replacing any existing content */
25
+ override(content) {
26
+ return this.chain(setProfile(content));
27
+ }
28
+ /** Updates specific fields in the profile content, merging with existing content */
29
+ update(content) {
30
+ return this.chain(updateProfile(content));
31
+ }
32
+ /** Sets the display name */
33
+ name(name) {
34
+ return this.chain(updateProfile({ name }));
35
+ }
36
+ /** Sets the username */
37
+ username(username) {
38
+ return this.chain(updateProfile({ username }));
39
+ }
40
+ /** Sets the display name (alias for name) */
41
+ displayName(displayName) {
42
+ return this.chain(updateProfile({ display_name: displayName }));
43
+ }
44
+ /** Sets the about/bio text */
45
+ about(about) {
46
+ return this.chain(updateProfile({ about }));
47
+ }
48
+ /** Sets the profile picture URL */
49
+ picture(picture) {
50
+ return this.chain(updateProfile({ picture }));
51
+ }
52
+ /** Sets the banner image URL */
53
+ banner(banner) {
54
+ return this.chain(updateProfile({ banner }));
55
+ }
56
+ /** Sets the website URL */
57
+ website(website) {
58
+ return this.chain(updateProfile({ website }));
59
+ }
60
+ /** Sets the NIP-05 identifier */
61
+ nip05(nip05) {
62
+ return this.chain(updateProfile({ nip05 }));
63
+ }
64
+ /** Sets the Lightning Network address */
65
+ lnurlp(lnurlp) {
66
+ return this.chain(updateProfile({ lud06: lnurlp }));
67
+ }
68
+ /** Sets the Lightning Network address (LNURL) */
69
+ lightningAddress(address) {
70
+ return this.chain(updateProfile({ lud16: address }));
71
+ }
72
+ /** Sets the bot flag */
73
+ bot(bot) {
74
+ return this.chain(updateProfile({ bot }));
75
+ }
76
+ /** Sets the languages */
77
+ languages(languages) {
78
+ return this.chain(updateProfile({ languages }));
79
+ }
80
+ }
@@ -0,0 +1,56 @@
1
+ import { EventTemplate, NostrEvent, UnsignedEvent } from "../helpers/event.js";
2
+ import { AddressPointer } from "../helpers/pointers.js";
3
+ /** Nostr event signer */
4
+ export interface EventSigner {
5
+ getPublicKey: () => Promise<string> | string;
6
+ signEvent: (draft: EventTemplate | UnsignedEvent) => Promise<NostrEvent> | NostrEvent;
7
+ nip04?: {
8
+ encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
9
+ decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
10
+ };
11
+ nip44?: {
12
+ encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
13
+ decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
14
+ };
15
+ }
16
+ /** A single operation that transforms a value (context-free) */
17
+ export type Operation<I extends unknown = unknown, R extends unknown = unknown> = (value: I) => R | Promise<R>;
18
+ /** A single operation that modifies an events public or hidden tags array */
19
+ export type TagOperation = Operation<string[][], string[][]>;
20
+ /** A single operation that modifies an event */
21
+ export type EventOperation<I extends EventTemplate | UnsignedEvent | NostrEvent = EventTemplate, R extends EventTemplate | UnsignedEvent | NostrEvent = EventTemplate> = Operation<I, R>;
22
+ /** NIP-30 emoji type */
23
+ export type Emoji = {
24
+ /** The emoji shortcode (without the ::) */
25
+ shortcode: string;
26
+ /** The URL to the emoji image */
27
+ url: string;
28
+ /** The NIP-01 "a" tag address of the emoji pack this emoji belongs to */
29
+ address?: AddressPointer;
30
+ };
31
+ /** A context with optional methods for getting relay hints */
32
+ export interface RelayHintContext {
33
+ getEventRelayHint?: (event: string) => string | undefined | Promise<string> | Promise<undefined>;
34
+ getPubkeyRelayHint?: (pubkey: string) => string | undefined | Promise<string> | Promise<undefined>;
35
+ }
36
+ export interface EventFactoryClient {
37
+ name: string;
38
+ address?: Omit<AddressPointer, "kind" | "relays">;
39
+ }
40
+ export interface EmojiContext {
41
+ /** An array of custom emojis that will be used for text notes */
42
+ emojis?: Emoji[];
43
+ }
44
+ /** Services that can be provided to event operations */
45
+ export interface EventFactoryServices {
46
+ /** Event signer for signing and stamping events */
47
+ signer?: EventSigner;
48
+ /** Function to get relay hint for an event ID */
49
+ getEventRelayHint?: (eventId: string) => Promise<string | undefined>;
50
+ /** Function to get relay hint for a pubkey */
51
+ getPubkeyRelayHint?: (pubkey: string) => Promise<string | undefined>;
52
+ /** Custom emojis for NIP-30 emoji tags */
53
+ emojis?: Emoji[];
54
+ /** NIP-89 client pointer */
55
+ client?: EventFactoryClient;
56
+ }
@@ -1,14 +1,23 @@
1
1
  import { kinds } from "nostr-tools";
2
+ import { isKind } from "nostr-tools/kinds";
2
3
  import { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind } from "nostr-tools/kinds";
3
- import { NostrEvent, VerifiedEvent } from "nostr-tools/pure";
4
+ import { EventTemplate, NostrEvent, UnsignedEvent, VerifiedEvent } from "nostr-tools/pure";
4
5
  import { IAsyncEventStore, IEventStore } from "../event-store/interface.js";
5
6
  export { EventTemplate, finalizeEvent, getEventHash, NostrEvent, serializeEvent, UnsignedEvent, VerifiedEvent, verifiedSymbol, verifyEvent, } from "nostr-tools/pure";
6
7
  export { binarySearch, bytesToHex, hexToBytes, insertEventIntoAscendingList, insertEventIntoDescendingList, } from "nostr-tools/utils";
7
- export { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind, kinds };
8
+ export { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind, kinds, isKind };
8
9
  /** An event with a known kind. this is used to know if events have been validated */
9
10
  export type KnownEvent<K extends number> = Omit<NostrEvent, "kind"> & {
10
11
  kind: K;
11
12
  };
13
+ /** An event template with a known kind. used in event factories */
14
+ export type KnownEventTemplate<K extends number> = Omit<EventTemplate, "kind"> & {
15
+ kind: K;
16
+ };
17
+ /** An unsigned event with a known kind. used in event factories */
18
+ export type KnownUnsignedEvent<K extends number> = Omit<UnsignedEvent, "kind"> & {
19
+ kind: K;
20
+ };
12
21
  /** A symbol on an event that marks which event store its part of */
13
22
  export declare const EventStoreSymbol: unique symbol;
14
23
  export declare const EventUIDSymbol: unique symbol;
@@ -1,11 +1,12 @@
1
1
  import { kinds } from "nostr-tools";
2
+ import { isKind } from "nostr-tools/kinds";
2
3
  import { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind } from "nostr-tools/kinds";
3
4
  import { verifiedSymbol, verifyEvent } from "nostr-tools/pure";
4
5
  import { getOrComputeCachedValue } from "./cache.js";
5
6
  // Re-export types from nostr-tools
6
7
  export { finalizeEvent, getEventHash, serializeEvent, verifiedSymbol, verifyEvent, } from "nostr-tools/pure";
7
8
  export { binarySearch, bytesToHex, hexToBytes, insertEventIntoAscendingList, insertEventIntoDescendingList, } from "nostr-tools/utils";
8
- export { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind, kinds };
9
+ export { isAddressableKind, isEphemeralKind, isRegularKind, isReplaceableKind, kinds, isKind };
9
10
  /** A symbol on an event that marks which event store its part of */
10
11
  export const EventStoreSymbol = Symbol.for("event-store");
11
12
  export const EventUIDSymbol = Symbol.for("event-uid");
@@ -1,7 +1,11 @@
1
- import { NostrEvent } from "./event.js";
1
+ import { kinds, KnownEvent, NostrEvent } from "./event.js";
2
+ /** Type for NIP-65 relay list events */
3
+ export type MailboxesEvent = KnownEvent<kinds.RelayList>;
2
4
  export declare const MailboxesInboxesSymbol: unique symbol;
3
5
  export declare const MailboxesOutboxesSymbol: unique symbol;
4
6
  /** Parses a 10002 event and stores the inboxes in the event using the {@link MailboxesInboxesSymbol} symbol */
5
7
  export declare function getInboxes(event: NostrEvent): string[];
6
8
  /** Parses a 10002 event and stores the outboxes in the event using the {@link MailboxesOutboxesSymbol} symbol */
7
9
  export declare function getOutboxes(event: NostrEvent): string[];
10
+ /** Checks if an event is a valid mailboxes event */
11
+ export declare function isMailboxesEvent(event: any): event is MailboxesEvent;
@@ -1,3 +1,4 @@
1
+ import { isKind, kinds } from "./event.js";
1
2
  import { getOrComputeCachedValue } from "./cache.js";
2
3
  import { isSafeRelayURL } from "./relays.js";
3
4
  import { isRTag } from "./tags.js";
@@ -47,3 +48,7 @@ export function getOutboxes(event) {
47
48
  return outboxes;
48
49
  });
49
50
  }
51
+ /** Checks if an event is a valid mailboxes event */
52
+ export function isMailboxesEvent(event) {
53
+ return isKind(event, kinds.RelayList);
54
+ }
@@ -1,4 +1,4 @@
1
- import { EventOperation, Operation, TagOperation } from "../event-factory/types.js";
1
+ import type { EventOperation, Operation, TagOperation } from "../factories/types.js";
2
2
  /** An array of Symbols to preserve when building events with {@link eventPipe} */
3
3
  export declare const PRESERVE_EVENT_SYMBOLS: Set<symbol>;
4
4
  export declare function identity<T>(x: T): T;
@@ -8,6 +8,19 @@ export declare function eventPipe(...operations: (EventOperation | undefined)[])
8
8
  export declare function tagPipe(...operations: (TagOperation | undefined)[]): TagOperation;
9
9
  /** A pipeline operation that does nothing */
10
10
  export declare function skip<T>(): (value: T) => T;
11
+ /**
12
+ * Pipe a value through a series of async operations
13
+ * @example
14
+ * ```ts
15
+ * const result = await pipe(
16
+ * draft,
17
+ * setContent("hello"),
18
+ * addTag("p", pubkey),
19
+ * sign(signer)
20
+ * );
21
+ * ```
22
+ */
23
+ export declare function pipe<T>(value: T, ...operations: Array<(v: any) => any | Promise<any>>): Promise<any>;
11
24
  /**
12
25
  * @param fns - An array of operations to pipe together
13
26
  * @param preserve - If set an array of symbols to keep, all other symbols will be removed
@@ -18,6 +18,21 @@ export function tagPipe(...operations) {
18
18
  export function skip() {
19
19
  return (value) => value;
20
20
  }
21
+ /**
22
+ * Pipe a value through a series of async operations
23
+ * @example
24
+ * ```ts
25
+ * const result = await pipe(
26
+ * draft,
27
+ * setContent("hello"),
28
+ * addTag("p", pubkey),
29
+ * sign(signer)
30
+ * );
31
+ * ```
32
+ */
33
+ export async function pipe(value, ...operations) {
34
+ return operations.reduce(async (prev, op) => op(await prev), Promise.resolve(value));
35
+ }
21
36
  /**
22
37
  * @param fns - An array of operations to pipe together
23
38
  * @param preserve - If set an array of symbols to keep, all other symbols will be removed
@@ -26,9 +41,9 @@ export function skip() {
26
41
  export function pipeFromAsyncArray(fns, preserve) {
27
42
  if (fns.length === 0)
28
43
  return identity;
29
- return async function piped(input, context) {
44
+ return async function piped(input) {
30
45
  return fns.reduce(async (prev, fn) => {
31
- const result = await fn(await prev, context);
46
+ const result = await fn(await prev);
32
47
  // Copy the symbols and fields if result is an object
33
48
  if (preserve && typeof result === "object" && result !== null && typeof prev === "object" && prev !== null) {
34
49
  const keys = Reflect.ownKeys(result).filter((key) => typeof key === "symbol");
@@ -4,42 +4,42 @@ export { decode as decodePointer, naddrEncode, neventEncode, noteEncode, nprofil
4
4
  export type { NAddr, NEvent, NProfile, NPub } from "nostr-tools/nip19";
5
5
  import { NostrEvent } from "./event.js";
6
6
  export type DecodeResult = DecodedResult;
7
- /** Decodes any nip-19 encoded entity to a ProfilePointer */
7
+ /** Decodes any NIP-19 encoded string into a ProfilePointer. Returns null if the string cannot be decoded. */
8
8
  export declare function decodeProfilePointer(str: string): ProfilePointer | null;
9
- /** Decodes an naddr encoded string to an AddressPointer */
9
+ /** Decodes an encoded NIP-19 naddr string to an AddressPointer. Returns null if the string cannot be decoded. */
10
10
  export declare function decodeAddressPointer(str: string): AddressPointer | null;
11
- /** Decodes a note1 or nevent encoded string to an EventPointer */
11
+ /** Decodes an encoded NIP-19 note1 or nevent string to an EventPointer. Returns null if the string cannot be decoded. */
12
12
  export declare function decodeEventPointer(str: string): EventPointer | null;
13
13
  export type AddressPointerWithoutD = Omit<AddressPointer, "identifier"> & {
14
14
  identifier?: string;
15
15
  };
16
- /** Parse the value of an "a" tag into an AddressPointer */
16
+ /** Parses the value of an "a" tag into an AddressPointer. Returns null if the address cannot be parsed. */
17
17
  export declare function parseReplaceableAddress(address: string, requireIdentifier?: boolean): AddressPointer | null;
18
- /** Extra a pubkey from the result of nip19.decode */
18
+ /** Extracts a pubkey from the result of nip19.decode Returns undefined if the decode result does not have a pubkey */
19
19
  export declare function getPubkeyFromDecodeResult(result?: DecodeResult): string | undefined;
20
- /** Gets the relays from a decode result */
20
+ /** Extracts the relays from a decode result */
21
21
  export declare function getRelaysFromDecodeResult(result?: DecodeResult): string[] | undefined;
22
- /** Encodes the result of nip19.decode */
22
+ /** Encodes the result of nip19.decode to a NIP-19 string. Returns an empty string if the result cannot be encoded. */
23
23
  export declare function encodeDecodeResult(result: DecodeResult): "" | `nevent1${string}` | `nprofile1${string}` | `naddr1${string}` | `nsec1${string}` | `npub1${string}` | `note1${string}`;
24
- /** Encodes a pointer to a NIP-19 string */
24
+ /** Encodes a pointer to a NIP-19 string. Returns an empty string if the pointer cannot be encoded. */
25
25
  export declare function encodePointer(pointer: AddressPointer | EventPointer | ProfilePointer): string;
26
- /** Gets an EventPointer form a common "e" tag */
26
+ /** Parses a common "e" tag into an EventPointer. Returns null if the tag cannot be parsed. */
27
27
  export declare function getEventPointerFromETag(tag: string[]): EventPointer | null;
28
- /** Gets an EventPointer form a common "q" tag */
28
+ /** Parses a common "q" tag into an EventPointer. Returns null if the tag cannot be parsed. */
29
29
  export declare function getEventPointerFromQTag(tag: string[]): EventPointer | null;
30
- /** Get an AddressPointer from a common "a" tag */
30
+ /** Parses a common "a" tag into an AddressPointer. Returns null if the tag cannot be parsed. */
31
31
  export declare function getAddressPointerFromATag(tag: string[]): AddressPointer | null;
32
- /** Gets a ProfilePointer from a common "p" tag */
32
+ /** Parses a common "p" tag into a ProfilePointer. Returns null if the tag cannot be parsed. */
33
33
  export declare function getProfilePointerFromPTag(tag: string[]): ProfilePointer | null;
34
- /** Checks if a pointer is an AddressPointer */
34
+ /** Checks if a pointer object is an AddressPointer */
35
35
  export declare function isAddressPointer(pointer: any): pointer is AddressPointer;
36
- /** Checks if a pointer is a ProfilePointer */
36
+ /** Checks if a pointer object is a ProfilePointer */
37
37
  export declare function isProfilePointer(pointer: any): pointer is ProfilePointer;
38
- /** Checks if a pointer is an EventPointer */
38
+ /** Checks if a pointer object is an EventPointer */
39
39
  export declare function isEventPointer(pointer: any): pointer is EventPointer;
40
- /** Returns the stringified address pointer */
40
+ /** Returns the stringified NIP-19 encoded naddr address pointer for an AddressPointer. */
41
41
  export declare function getReplaceableAddressFromPointer(pointer: AddressPointer): string;
42
- /** Returns an AddressPointer for a replaceable event */
42
+ /** Returns an AddressPointer for a replaceable event. Returns null if the event is not addressable or replaceable. */
43
43
  export declare function getAddressPointerForEvent(event: NostrEvent, relays?: string[]): AddressPointer | null;
44
44
  /** Returns an EventPointer for an event */
45
45
  export declare function getEventPointerForEvent(event: NostrEvent, relays?: string[]): EventPointer;
@@ -49,17 +49,17 @@ export declare function getPointerForEvent(event: NostrEvent, relays?: string[])
49
49
  export declare function addRelayHintsToPointer<T extends {
50
50
  relays?: string[];
51
51
  }>(pointer: T, relays?: Iterable<string>): T;
52
- /** Gets the hex pubkey from any nip-19 encoded string */
52
+ /** Parses any nip-19 encoded string into a hex pubkey. Returns null if the string is not a valid pubkey. */
53
53
  export declare function normalizeToPubkey(str: NPub): string;
54
54
  export declare function normalizeToPubkey(str: string): string | null;
55
- /** Gets a ProfilePointer from any nip-19 encoded string */
55
+ /** Parses any nip-19 encoded string into a ProfilePointer. Returns null if the string cannot be parsed. */
56
56
  export declare function normalizeToProfilePointer(str: NProfile): ProfilePointer;
57
57
  export declare function normalizeToProfilePointer(str: NPub): ProfilePointer;
58
58
  export declare function normalizeToProfilePointer(str: string): ProfilePointer | null;
59
- /** Gets an AddressPointer from any nip-19 encoded string */
59
+ /** Parses any nip-19 encoded string into an AddressPointer. Returns null if the string cannot be parsed. */
60
60
  export declare function normalizeToAddressPointer(str: NAddr): AddressPointer;
61
61
  export declare function normalizeToAddressPointer(str: string): AddressPointer | null;
62
- /** Gets an EventPointer from any nip-19 encoded string */
62
+ /** Parses any nip-19 encoded string into an EventPointer. Returns null if the string cannot be parsed. */
63
63
  export declare function normalizeToEventPointer(str: NEvent): EventPointer;
64
64
  export declare function normalizeToEventPointer(str: string): EventPointer | null;
65
65
  /** Returns all NIP-19 pointers in a content string */
@@ -79,5 +79,9 @@ export declare function mergeAddressPointers(a: AddressPointer, b: AddressPointe
79
79
  * @throws if the pubkeys are different
80
80
  */
81
81
  export declare function mergeProfilePointers(a: ProfilePointer, b: ProfilePointer): ProfilePointer;
82
+ /** Checks if two address pointers refer to the same addressable event. Ignores relays. */
83
+ export declare function isAddressPointerSame(a: AddressPointer, b: AddressPointer): boolean;
84
+ /** Checks if two event pointers refer to the same event. Ignores relays. */
85
+ export declare function isEventPointerSame(a: EventPointer, b: EventPointer): boolean;
82
86
  /** Checks if an event matches a pointer */
83
87
  export declare function eventMatchesPointer(event: NostrEvent, pointer: EventPointer | AddressPointer | AddressPointerWithoutD): boolean;
@@ -7,7 +7,7 @@ import { Tokens } from "./regexp.js";
7
7
  import { isSafeRelayURL, relaySet } from "./relays.js";
8
8
  import { isHexKey } from "./string.js";
9
9
  import { normalizeURL } from "./url.js";
10
- /** Decodes a string and handles errors */
10
+ /** Decodes a string and handles errors. Returns null if the string cannot be decoded. */
11
11
  function safeDecode(str) {
12
12
  try {
13
13
  return decode(str);
@@ -16,7 +16,7 @@ function safeDecode(str) {
16
16
  return null;
17
17
  }
18
18
  }
19
- /** Decodes any nip-19 encoded entity to a ProfilePointer */
19
+ /** Decodes any NIP-19 encoded string into a ProfilePointer. Returns null if the string cannot be decoded. */
20
20
  export function decodeProfilePointer(str) {
21
21
  const result = safeDecode(str);
22
22
  if (!result)
@@ -29,14 +29,14 @@ export function decodeProfilePointer(str) {
29
29
  relays: getRelaysFromDecodeResult(result),
30
30
  };
31
31
  }
32
- /** Decodes an naddr encoded string to an AddressPointer */
32
+ /** Decodes an encoded NIP-19 naddr string to an AddressPointer. Returns null if the string cannot be decoded. */
33
33
  export function decodeAddressPointer(str) {
34
34
  const result = safeDecode(str);
35
35
  if (!result)
36
36
  return null;
37
37
  return result.type === "naddr" ? result.data : null;
38
38
  }
39
- /** Decodes a note1 or nevent encoded string to an EventPointer */
39
+ /** Decodes an encoded NIP-19 note1 or nevent string to an EventPointer. Returns null if the string cannot be decoded. */
40
40
  export function decodeEventPointer(str) {
41
41
  const result = safeDecode(str);
42
42
  if (!result)
@@ -50,7 +50,7 @@ export function decodeEventPointer(str) {
50
50
  return null;
51
51
  }
52
52
  }
53
- /** Parse the value of an "a" tag into an AddressPointer */
53
+ /** Parses the value of an "a" tag into an AddressPointer. Returns null if the address cannot be parsed. */
54
54
  export function parseReplaceableAddress(address, requireIdentifier = false) {
55
55
  const parts = address.split(":");
56
56
  const kind = parts[0] ? parseInt(parts[0]) : undefined;
@@ -73,7 +73,7 @@ export function parseReplaceableAddress(address, requireIdentifier = false) {
73
73
  identifier,
74
74
  };
75
75
  }
76
- /** Extra a pubkey from the result of nip19.decode */
76
+ /** Extracts a pubkey from the result of nip19.decode Returns undefined if the decode result does not have a pubkey */
77
77
  export function getPubkeyFromDecodeResult(result) {
78
78
  if (!result)
79
79
  return;
@@ -89,7 +89,7 @@ export function getPubkeyFromDecodeResult(result) {
89
89
  return undefined;
90
90
  }
91
91
  }
92
- /** Gets the relays from a decode result */
92
+ /** Extracts the relays from a decode result */
93
93
  export function getRelaysFromDecodeResult(result) {
94
94
  if (!result)
95
95
  return;
@@ -103,7 +103,7 @@ export function getRelaysFromDecodeResult(result) {
103
103
  }
104
104
  return undefined;
105
105
  }
106
- /** Encodes the result of nip19.decode */
106
+ /** Encodes the result of nip19.decode to a NIP-19 string. Returns an empty string if the result cannot be encoded. */
107
107
  export function encodeDecodeResult(result) {
108
108
  switch (result.type) {
109
109
  case "naddr":
@@ -121,7 +121,7 @@ export function encodeDecodeResult(result) {
121
121
  }
122
122
  return "";
123
123
  }
124
- /** Encodes a pointer to a NIP-19 string */
124
+ /** Encodes a pointer to a NIP-19 string. Returns an empty string if the pointer cannot be encoded. */
125
125
  export function encodePointer(pointer) {
126
126
  if (isAddressPointer(pointer))
127
127
  return naddrEncode(pointer);
@@ -132,7 +132,7 @@ export function encodePointer(pointer) {
132
132
  else
133
133
  return "";
134
134
  }
135
- /** Gets an EventPointer form a common "e" tag */
135
+ /** Parses a common "e" tag into an EventPointer. Returns null if the tag cannot be parsed. */
136
136
  export function getEventPointerFromETag(tag) {
137
137
  const id = tag[1];
138
138
  if (!id || !isHexKey(id))
@@ -142,7 +142,7 @@ export function getEventPointerFromETag(tag) {
142
142
  pointer.relays = [normalizeURL(tag[2])];
143
143
  return pointer;
144
144
  }
145
- /** Gets an EventPointer form a common "q" tag */
145
+ /** Parses a common "q" tag into an EventPointer. Returns null if the tag cannot be parsed. */
146
146
  export function getEventPointerFromQTag(tag) {
147
147
  const id = tag[1];
148
148
  if (!id || !isHexKey(id))
@@ -154,7 +154,7 @@ export function getEventPointerFromQTag(tag) {
154
154
  pointer.author = tag[3];
155
155
  return pointer;
156
156
  }
157
- /** Get an AddressPointer from a common "a" tag */
157
+ /** Parses a common "a" tag into an AddressPointer. Returns null if the tag cannot be parsed. */
158
158
  export function getAddressPointerFromATag(tag) {
159
159
  if (!tag[1])
160
160
  return null;
@@ -165,7 +165,7 @@ export function getAddressPointerFromATag(tag) {
165
165
  pointer.relays = [normalizeURL(tag[2])];
166
166
  return pointer;
167
167
  }
168
- /** Gets a ProfilePointer from a common "p" tag */
168
+ /** Parses a common "p" tag into a ProfilePointer. Returns null if the tag cannot be parsed. */
169
169
  export function getProfilePointerFromPTag(tag) {
170
170
  const pubkey = tag[1];
171
171
  if (!pubkey || !isHexKey(pubkey))
@@ -175,7 +175,7 @@ export function getProfilePointerFromPTag(tag) {
175
175
  pointer.relays = [normalizeURL(tag[2])];
176
176
  return pointer;
177
177
  }
178
- /** Checks if a pointer is an AddressPointer */
178
+ /** Checks if a pointer object is an AddressPointer */
179
179
  export function isAddressPointer(pointer) {
180
180
  return (typeof pointer === "object" &&
181
181
  pointer !== null &&
@@ -186,7 +186,7 @@ export function isAddressPointer(pointer) {
186
186
  typeof pointer.pubkey === "string" &&
187
187
  typeof pointer.kind === "number");
188
188
  }
189
- /** Checks if a pointer is a ProfilePointer */
189
+ /** Checks if a pointer object is a ProfilePointer */
190
190
  export function isProfilePointer(pointer) {
191
191
  return (typeof pointer === "object" &&
192
192
  pointer !== null &&
@@ -196,15 +196,15 @@ export function isProfilePointer(pointer) {
196
196
  !isEventPointer(pointer) &&
197
197
  !isAddressPointer(pointer));
198
198
  }
199
- /** Checks if a pointer is an EventPointer */
199
+ /** Checks if a pointer object is an EventPointer */
200
200
  export function isEventPointer(pointer) {
201
201
  return typeof pointer === "object" && pointer !== null && "id" in pointer && typeof pointer.id === "string";
202
202
  }
203
- /** Returns the stringified address pointer */
203
+ /** Returns the stringified NIP-19 encoded naddr address pointer for an AddressPointer. */
204
204
  export function getReplaceableAddressFromPointer(pointer) {
205
205
  return pointer.kind + ":" + pointer.pubkey + ":" + pointer.identifier;
206
206
  }
207
- /** Returns an AddressPointer for a replaceable event */
207
+ /** Returns an AddressPointer for a replaceable event. Returns null if the event is not addressable or replaceable. */
208
208
  export function getAddressPointerForEvent(event, relays) {
209
209
  if (!isAddressableKind(event.kind) && !isReplaceableKind(event.kind))
210
210
  return null;
@@ -345,6 +345,21 @@ export function mergeProfilePointers(a, b) {
345
345
  const relays = relaySet(a.relays, b.relays);
346
346
  return { ...a, relays };
347
347
  }
348
+ /** Checks if two address pointers refer to the same addressable event. Ignores relays. */
349
+ export function isAddressPointerSame(a, b) {
350
+ return a.kind === b.kind && a.pubkey === b.pubkey && a.identifier === b.identifier;
351
+ }
352
+ /** Checks if two event pointers refer to the same event. Ignores relays. */
353
+ export function isEventPointerSame(a, b) {
354
+ return (
355
+ // Check if id is the same
356
+ a.id === b.id &&
357
+ // Because event id's are unique, we can skip extra checks if either pointer is missing some fields
358
+ // If any kind is undefined, ignore it
359
+ (a.kind !== undefined || b.kind !== undefined ? a.kind === b.kind : true) &&
360
+ // If any author is undefined, ignore it
361
+ (a.author !== undefined || b.author !== undefined ? a.author === b.author : true));
362
+ }
348
363
  /** Checks if an event matches a pointer */
349
364
  export function eventMatchesPointer(event, pointer) {
350
365
  if (isEventPointer(pointer)) {
@@ -19,10 +19,10 @@ export type ProfileContent = {
19
19
  banner?: string;
20
20
  /** A web URL related in any way to the event author */
21
21
  website?: string;
22
+ /** A LNURL-based Lightning address in the format `lnurlp://…` */
23
+ lud06?: string;
22
24
  /** Lightning address in the format `user@domain.com` (LUD-16 format) */
23
25
  lud16?: string;
24
- /** Lightning address in the format `user@domain.com` (LUD-06 format) */
25
- lud06?: string;
26
26
  /** DNS-based verification identifier in the format `_@domain.com` or `user@domain.com` */
27
27
  nip05?: string;
28
28
  /** Boolean to clarify that the content is entirely or partially the result of automation, such as with chatbots or newsfeeds */
@@ -6,6 +6,7 @@ export declare const Expressions: {
6
6
  readonly emoji: RegExp;
7
7
  readonly hashtag: RegExp;
8
8
  readonly lightning: RegExp;
9
+ readonly blossom: RegExp;
9
10
  };
10
11
  /** A list of Regular Expressions that match tokens surrounded by whitespace to avoid matching in URLs */
11
12
  export declare const Tokens: {
@@ -16,4 +17,5 @@ export declare const Tokens: {
16
17
  readonly emoji: RegExp;
17
18
  readonly hashtag: RegExp;
18
19
  readonly lightning: RegExp;
20
+ readonly blossom: RegExp;
19
21
  };
@@ -1,9 +1,9 @@
1
1
  export const Expressions = {
2
2
  get url() {
3
- return /(?:https?|wss?|ircs?|s?ftp):\/\/([a-zA-Z0-9\.\-]+\.[a-zA-Z]+(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
3
+ return /(?:https?|wss?|ircs?|s?ftp):\/\/((?:(?:\d{1,3}\.){3}\d{1,3}|localhost|[a-zA-Z0-9\.\-]+\.[a-zA-Z]+)(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
4
4
  },
5
5
  get link() {
6
- return /https?:\/\/([a-zA-Z0-9\.\-]+\.[a-zA-Z]+(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
6
+ return /https?:\/\/((?:(?:\d{1,3}\.){3}\d{1,3}|localhost|[a-zA-Z0-9\.\-]+\.[a-zA-Z]+)(?::\d+)?)([\/\?#][\p{L}\p{N}\p{M}&\.-\/\?=#\-@%\+_,:!~*]*)?/gu;
7
7
  },
8
8
  get cashu() {
9
9
  return /(?:cashu:\/{0,2})?(cashu(?:A|B)[A-Za-z0-9_-]{100,}={0,3})/gi;
@@ -21,6 +21,9 @@ export const Expressions = {
21
21
  get lightning() {
22
22
  return /(?:lightning:)?(LNBC[A-Za-z0-9]+)/gim;
23
23
  },
24
+ get blossom() {
25
+ return /blossom:([0-9a-f]{64})\.([a-zA-Z0-9]+)(\?[^\s]*)?/g;
26
+ },
24
27
  };
25
28
  /** A list of Regular Expressions that match tokens surrounded by whitespace to avoid matching in URLs */
26
29
  export const Tokens = {
@@ -45,4 +48,7 @@ export const Tokens = {
45
48
  get lightning() {
46
49
  return new RegExp(`(?<=^|\\s)${Expressions.lightning.source}`, "gim");
47
50
  },
51
+ get blossom() {
52
+ return new RegExp(`(?<=^|\\s)${Expressions.blossom.source}`, "g");
53
+ },
48
54
  };
@@ -1,5 +1,7 @@
1
1
  import { NostrEvent } from "./event.js";
2
2
  export declare const SeenRelaysSymbol: unique symbol;
3
+ /** Normalizes a relay URL by using {@link normalizeURL} and {@link ensureWebSocketURL} */
4
+ export declare function normalizeRelayUrl(input: string): string;
3
5
  /** Marks an event as being seen on a relay */
4
6
  export declare function addSeenRelay(event: NostrEvent, relay: string): Set<string>;
5
7
  /** Returns the set of relays this event was seen on */
@@ -9,6 +11,6 @@ export declare function isFromRelay(event: NostrEvent, relay: string): boolean;
9
11
  /** A fast check to make sure relay hints are safe to connect to */
10
12
  export declare function isSafeRelayURL(relay: string): boolean;
11
13
  /** Merge multiple sets of relays and remove duplicates (ignores invalid URLs) */
12
- export declare function mergeRelaySets(...sources: (Iterable<string> | string | undefined)[]): string[];
14
+ export declare function mergeRelaySets(...sources: (Iterable<string> | string | undefined | null)[]): string[];
13
15
  /** Alias for {@link mergeRelaySets} */
14
16
  export declare const relaySet: typeof mergeRelaySets;
@@ -1,5 +1,9 @@
1
- import { normalizeURL } from "./url.js";
1
+ import { ensureWebSocketURL, normalizeURL } from "./url.js";
2
2
  export const SeenRelaysSymbol = Symbol.for("seen-relays");
3
+ /** Normalizes a relay URL by using {@link normalizeURL} and {@link ensureWebSocketURL} */
4
+ export function normalizeRelayUrl(input) {
5
+ return normalizeURL(ensureWebSocketURL(input));
6
+ }
3
7
  /** Marks an event as being seen on a relay */
4
8
  export function addSeenRelay(event, relay) {
5
9
  let seen = Reflect.get(event, SeenRelaysSymbol);
@@ -34,23 +38,17 @@ export function mergeRelaySets(...sources) {
34
38
  if (!src)
35
39
  continue;
36
40
  if (typeof src === "string") {
37
- // Source is a string
38
41
  try {
39
- const safe = normalizeURL(src).toString();
40
- if (safe)
41
- set.add(safe);
42
+ set.add(normalizeRelayUrl(src));
42
43
  }
43
44
  catch (error) {
44
45
  // failed to parse URL, ignore
45
46
  }
46
47
  }
47
- else {
48
- // Source is iterable
48
+ else if (Reflect.has(src, Symbol.iterator)) {
49
49
  for (const url of src) {
50
50
  try {
51
- const safe = normalizeURL(url).toString();
52
- if (safe)
53
- set.add(safe);
51
+ set.add(normalizeRelayUrl(url));
54
52
  }
55
53
  catch (error) {
56
54
  // failed to parse URL, ignore