applesauce-core 0.9.0 → 0.11.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.
- package/README.md +1 -1
- package/dist/__tests__/fixtures.d.ts +8 -0
- package/dist/__tests__/fixtures.js +20 -0
- package/dist/event-store/__tests__/event-store.test.js +259 -0
- package/dist/event-store/database.d.ts +22 -16
- package/dist/event-store/database.js +62 -39
- package/dist/event-store/event-store.d.ts +52 -15
- package/dist/event-store/event-store.js +283 -191
- package/dist/helpers/__tests__/blossom.test.d.ts +1 -0
- package/dist/helpers/__tests__/blossom.test.js +13 -0
- package/dist/helpers/__tests__/comment.test.d.ts +1 -0
- package/dist/helpers/__tests__/comment.test.js +235 -0
- package/dist/helpers/__tests__/emoji.test.d.ts +1 -0
- package/dist/helpers/__tests__/emoji.test.js +15 -0
- package/dist/helpers/__tests__/event.test.d.ts +1 -0
- package/dist/helpers/__tests__/event.test.js +36 -0
- package/dist/helpers/__tests__/file-metadata.test.d.ts +1 -0
- package/dist/helpers/__tests__/file-metadata.test.js +103 -0
- package/dist/helpers/__tests__/hidden-tags.test.d.ts +1 -0
- package/dist/helpers/__tests__/hidden-tags.test.js +29 -0
- package/dist/helpers/__tests__/mailboxes.test.d.ts +1 -0
- package/dist/helpers/{mailboxes.test.js → __tests__/mailboxes.test.js} +14 -13
- package/dist/helpers/__tests__/relays.test.d.ts +1 -0
- package/dist/helpers/__tests__/relays.test.js +21 -0
- package/dist/helpers/__tests__/tags.test.d.ts +1 -0
- package/dist/helpers/__tests__/tags.test.js +24 -0
- package/dist/helpers/__tests__/threading.test.d.ts +1 -0
- package/dist/helpers/__tests__/threading.test.js +41 -0
- package/dist/helpers/blossom.d.ts +9 -0
- package/dist/helpers/blossom.js +22 -0
- package/dist/helpers/bolt11.d.ts +1 -0
- package/dist/helpers/bolt11.js +1 -0
- package/dist/helpers/bookmarks.d.ts +15 -0
- package/dist/helpers/bookmarks.js +27 -0
- package/dist/helpers/channels.d.ts +10 -0
- package/dist/helpers/channels.js +27 -0
- package/dist/helpers/comment.d.ts +47 -0
- package/dist/helpers/comment.js +120 -0
- package/dist/helpers/contacts.d.ts +3 -0
- package/dist/helpers/contacts.js +25 -0
- package/dist/helpers/content.d.ts +3 -0
- package/dist/helpers/content.js +8 -0
- package/dist/helpers/delete.d.ts +3 -0
- package/dist/helpers/delete.js +7 -0
- package/dist/helpers/dns-identity.d.ts +7 -0
- package/dist/helpers/dns-identity.js +10 -0
- package/dist/helpers/emoji.d.ts +12 -1
- package/dist/helpers/emoji.js +13 -1
- package/dist/helpers/event.d.ts +17 -3
- package/dist/helpers/event.js +54 -12
- package/dist/helpers/external-id.d.ts +29 -0
- package/dist/helpers/external-id.js +20 -0
- package/dist/helpers/file-metadata.d.ts +55 -0
- package/dist/helpers/file-metadata.js +99 -0
- package/dist/helpers/filter.d.ts +4 -2
- package/dist/helpers/filter.js +36 -7
- package/dist/helpers/groups.d.ts +24 -0
- package/dist/helpers/groups.js +39 -0
- package/dist/helpers/hidden-tags.d.ts +48 -0
- package/dist/helpers/hidden-tags.js +86 -0
- package/dist/helpers/index.d.ts +28 -8
- package/dist/helpers/index.js +28 -8
- package/dist/helpers/json.d.ts +1 -0
- package/dist/helpers/json.js +1 -0
- package/dist/helpers/lists.d.ts +28 -0
- package/dist/helpers/lists.js +65 -0
- package/dist/helpers/lnurl.d.ts +4 -0
- package/dist/helpers/lnurl.js +40 -0
- package/dist/helpers/mailboxes.js +16 -9
- package/dist/helpers/mutes.d.ts +14 -0
- package/dist/helpers/mutes.js +23 -0
- package/dist/helpers/picture-post.d.ts +4 -0
- package/dist/helpers/picture-post.js +6 -0
- package/dist/helpers/pointers.d.ts +38 -5
- package/dist/helpers/pointers.js +105 -25
- package/dist/helpers/profile.d.ts +6 -1
- package/dist/helpers/profile.js +5 -1
- package/dist/helpers/relays.d.ts +6 -3
- package/dist/helpers/relays.js +25 -18
- package/dist/helpers/share.d.ts +4 -0
- package/dist/helpers/share.js +12 -0
- package/dist/helpers/string.d.ts +6 -0
- package/dist/helpers/string.js +2 -0
- package/dist/helpers/tags.d.ts +23 -0
- package/dist/helpers/tags.js +34 -6
- package/dist/helpers/threading.d.ts +6 -6
- package/dist/helpers/threading.js +30 -9
- package/dist/helpers/url.d.ts +11 -1
- package/dist/helpers/url.js +31 -3
- package/dist/helpers/user-status.d.ts +18 -0
- package/dist/helpers/user-status.js +21 -0
- package/dist/helpers/zap.d.ts +25 -0
- package/dist/helpers/zap.js +32 -3
- package/dist/observable/__tests__/claim-events.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-events.test.js +23 -0
- package/dist/observable/__tests__/claim-latest.test.d.ts +1 -0
- package/dist/observable/__tests__/claim-latest.test.js +37 -0
- package/dist/observable/__tests__/simple-timeout.test.d.ts +1 -0
- package/dist/observable/__tests__/simple-timeout.test.js +34 -0
- package/dist/observable/claim-events.d.ts +5 -0
- package/dist/observable/claim-events.js +28 -0
- package/dist/observable/claim-latest.d.ts +4 -0
- package/dist/observable/claim-latest.js +20 -0
- package/dist/observable/get-observable-value.d.ts +3 -0
- package/dist/observable/get-observable-value.js +9 -0
- package/dist/observable/index.d.ts +2 -1
- package/dist/observable/index.js +2 -1
- package/dist/observable/share-latest-value.d.ts +2 -4
- package/dist/observable/share-latest-value.js +19 -16
- package/dist/observable/simple-timeout.d.ts +4 -0
- package/dist/observable/simple-timeout.js +6 -0
- package/dist/promise/deferred.d.ts +1 -0
- package/dist/promise/deferred.js +1 -0
- package/dist/queries/blossom.d.ts +2 -0
- package/dist/queries/blossom.js +10 -0
- package/dist/queries/bookmarks.d.ts +8 -0
- package/dist/queries/bookmarks.js +23 -0
- package/dist/queries/channels.d.ts +11 -0
- package/dist/queries/channels.js +73 -0
- package/dist/queries/comments.d.ts +4 -0
- package/dist/queries/comments.js +14 -0
- package/dist/queries/contacts.d.ts +3 -0
- package/dist/queries/contacts.js +12 -0
- package/dist/queries/index.d.ts +9 -2
- package/dist/queries/index.js +9 -2
- package/dist/queries/mailboxes.d.ts +1 -0
- package/dist/queries/mailboxes.js +1 -0
- package/dist/queries/mutes.d.ts +8 -0
- package/dist/queries/mutes.js +23 -0
- package/dist/queries/pins.d.ts +3 -0
- package/dist/queries/pins.js +12 -0
- package/dist/queries/profile.d.ts +1 -0
- package/dist/queries/profile.js +1 -0
- package/dist/queries/reactions.d.ts +1 -1
- package/dist/queries/reactions.js +1 -1
- package/dist/queries/simple.d.ts +4 -4
- package/dist/queries/simple.js +13 -13
- package/dist/queries/thread.d.ts +2 -0
- package/dist/queries/thread.js +30 -4
- package/dist/queries/user-status.d.ts +11 -0
- package/dist/queries/user-status.js +39 -0
- package/dist/queries/zaps.d.ts +1 -0
- package/dist/queries/zaps.js +1 -0
- package/dist/query-store/index.d.ts +1 -47
- package/dist/query-store/index.js +1 -60
- package/dist/query-store/query-store.d.ts +51 -0
- package/dist/query-store/query-store.js +88 -0
- package/dist/query-store/query-store.test.d.ts +1 -0
- package/dist/query-store/query-store.test.js +33 -0
- package/package.json +24 -21
- package/dist/observable/getValue.d.ts +0 -2
- package/dist/observable/getValue.js +0 -13
- /package/dist/{helpers/mailboxes.test.d.ts → event-store/__tests__/event-store.test.d.ts} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { bech32 } from "@scure/base";
|
|
2
|
+
import { parseBolt11 } from "./bolt11.js";
|
|
3
|
+
const decoder = new TextDecoder();
|
|
4
|
+
export function parseLightningAddress(address) {
|
|
5
|
+
let [name, domain] = address.split("@");
|
|
6
|
+
if (!name || !domain)
|
|
7
|
+
return;
|
|
8
|
+
return new URL(`https://${domain}/.well-known/lnurlp/${name}`);
|
|
9
|
+
}
|
|
10
|
+
export function decodeLNURL(lnurl) {
|
|
11
|
+
try {
|
|
12
|
+
const { words, prefix } = bech32.decode(lnurl);
|
|
13
|
+
if (prefix !== "lnurl")
|
|
14
|
+
return;
|
|
15
|
+
const str = decoder.decode(bech32.fromWords(words));
|
|
16
|
+
return new URL(str);
|
|
17
|
+
}
|
|
18
|
+
catch (error) { }
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
export function parseLNURLOrAddress(addressOrLNURL) {
|
|
22
|
+
if (addressOrLNURL.includes("@")) {
|
|
23
|
+
return parseLightningAddress(addressOrLNURL);
|
|
24
|
+
}
|
|
25
|
+
return decodeLNURL(addressOrLNURL);
|
|
26
|
+
}
|
|
27
|
+
export async function getInvoice(callback) {
|
|
28
|
+
const { pr: payRequest } = await fetch(callback).then((res) => res.json());
|
|
29
|
+
const amount = callback.searchParams.get("amount");
|
|
30
|
+
if (!amount)
|
|
31
|
+
throw new Error("Missing amount");
|
|
32
|
+
if (payRequest) {
|
|
33
|
+
const parsed = parseBolt11(payRequest);
|
|
34
|
+
if (parsed.amount !== parseInt(amount))
|
|
35
|
+
throw new Error("Incorrect amount");
|
|
36
|
+
return payRequest;
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
throw new Error("Failed to get invoice");
|
|
40
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { safeRelayUrl } from "./relays.js";
|
|
2
1
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
import { isSafeRelayURL } from "./relays.js";
|
|
3
|
+
import { normalizeURL } from "./url.js";
|
|
3
4
|
export const MailboxesInboxesSymbol = Symbol.for("mailboxes-inboxes");
|
|
4
5
|
export const MailboxesOutboxesSymbol = Symbol.for("mailboxes-outboxes");
|
|
5
6
|
/**
|
|
@@ -9,10 +10,13 @@ export function getInboxes(event) {
|
|
|
9
10
|
return getOrComputeCachedValue(event, MailboxesInboxesSymbol, () => {
|
|
10
11
|
const inboxes = [];
|
|
11
12
|
for (const tag of event.tags) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const [name, url, mode] = tag;
|
|
14
|
+
if (name === "r" &&
|
|
15
|
+
url &&
|
|
16
|
+
isSafeRelayURL(url) &&
|
|
17
|
+
!inboxes.includes(url) &&
|
|
18
|
+
(mode === "read" || mode === undefined)) {
|
|
19
|
+
inboxes.push(normalizeURL(url));
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
return inboxes;
|
|
@@ -25,10 +29,13 @@ export function getOutboxes(event) {
|
|
|
25
29
|
return getOrComputeCachedValue(event, MailboxesOutboxesSymbol, () => {
|
|
26
30
|
const outboxes = [];
|
|
27
31
|
for (const tag of event.tags) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
const [name, url, mode] = tag;
|
|
33
|
+
if (name === "r" &&
|
|
34
|
+
url &&
|
|
35
|
+
isSafeRelayURL(url) &&
|
|
36
|
+
!outboxes.includes(url) &&
|
|
37
|
+
(mode === "write" || mode === undefined)) {
|
|
38
|
+
outboxes.push(normalizeURL(url));
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
return outboxes;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
export declare const MutePublicSymbol: unique symbol;
|
|
3
|
+
export declare const MuteHiddenSymbol: unique symbol;
|
|
4
|
+
export type Mutes = {
|
|
5
|
+
pubkeys: Set<string>;
|
|
6
|
+
threads: Set<string>;
|
|
7
|
+
hashtags: Set<string>;
|
|
8
|
+
words: Set<string>;
|
|
9
|
+
};
|
|
10
|
+
export declare function parseMutedTags(tags: string[][]): Mutes;
|
|
11
|
+
/** Returns muted things */
|
|
12
|
+
export declare function getMutedThings(mute: NostrEvent): Mutes;
|
|
13
|
+
/** Returns the hidden muted content if the event is unlocked */
|
|
14
|
+
export declare function getHiddenMutedThings(mute: NostrEvent): Mutes | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isETag, isPTag, isTTag } from "./tags.js";
|
|
2
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
|
+
import { getHiddenTags } from "./hidden-tags.js";
|
|
4
|
+
export const MutePublicSymbol = Symbol.for("mute-public");
|
|
5
|
+
export const MuteHiddenSymbol = Symbol.for("mute-hidden");
|
|
6
|
+
export function parseMutedTags(tags) {
|
|
7
|
+
const pubkeys = new Set(tags.filter(isPTag).map((t) => t[1]));
|
|
8
|
+
const threads = new Set(tags.filter(isETag).map((t) => t[1]));
|
|
9
|
+
const hashtags = new Set(tags.filter(isTTag).map((t) => t[1].toLocaleLowerCase()));
|
|
10
|
+
const words = new Set(tags.filter((t) => t[0] === "word" && t[1]).map((t) => t[1].toLocaleLowerCase()));
|
|
11
|
+
return { pubkeys, threads, hashtags, words };
|
|
12
|
+
}
|
|
13
|
+
/** Returns muted things */
|
|
14
|
+
export function getMutedThings(mute) {
|
|
15
|
+
return getOrComputeCachedValue(mute, MutePublicSymbol, (e) => parseMutedTags(e.tags));
|
|
16
|
+
}
|
|
17
|
+
/** Returns the hidden muted content if the event is unlocked */
|
|
18
|
+
export function getHiddenMutedThings(mute) {
|
|
19
|
+
return getOrComputeCachedValue(mute, MuteHiddenSymbol, () => {
|
|
20
|
+
const tags = getHiddenTags(mute);
|
|
21
|
+
return tags && parseMutedTags(tags);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -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;
|
|
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}`;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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;
|
package/dist/helpers/pointers.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode, } from "nostr-tools/nip19";
|
|
2
|
-
import { getPublicKey } from "nostr-tools";
|
|
3
|
-
import {
|
|
2
|
+
import { getPublicKey, kinds } from "nostr-tools";
|
|
3
|
+
import { getReplaceableIdentifier } from "./event.js";
|
|
4
|
+
import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
|
|
5
|
+
import { isSafeRelayURL } from "./relays.js";
|
|
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":
|
|
@@ -62,42 +66,72 @@ export function encodeDecodeResult(result) {
|
|
|
62
66
|
}
|
|
63
67
|
return "";
|
|
64
68
|
}
|
|
65
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Gets an EventPointer form a common "e" tag
|
|
71
|
+
* @throws
|
|
72
|
+
*/
|
|
73
|
+
export function getEventPointerFromETag(tag) {
|
|
66
74
|
if (!tag[1])
|
|
67
75
|
throw new Error("Missing event id in tag");
|
|
68
76
|
let pointer = { id: tag[1] };
|
|
69
|
-
if (tag[2])
|
|
70
|
-
pointer.relays =
|
|
77
|
+
if (tag[2] && isSafeRelayURL(tag[2]))
|
|
78
|
+
pointer.relays = [tag[2]];
|
|
71
79
|
return pointer;
|
|
72
80
|
}
|
|
73
|
-
|
|
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] && isSafeRelayURL(tag[2]))
|
|
90
|
+
pointer.relays = [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) {
|
|
74
100
|
if (!tag[1])
|
|
75
101
|
throw new Error("Missing coordinate in tag");
|
|
76
102
|
const pointer = parseCoordinate(tag[1], true, false);
|
|
77
|
-
if (tag[2])
|
|
78
|
-
pointer.relays =
|
|
103
|
+
if (tag[2] && isSafeRelayURL(tag[2]))
|
|
104
|
+
pointer.relays = [tag[2]];
|
|
79
105
|
return pointer;
|
|
80
106
|
}
|
|
81
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Gets a ProfilePointer from a "p" tag
|
|
109
|
+
* @throws
|
|
110
|
+
*/
|
|
111
|
+
export function getProfilePointerFromPTag(tag) {
|
|
82
112
|
if (!tag[1])
|
|
83
113
|
throw new Error("Missing pubkey in tag");
|
|
84
114
|
const pointer = { pubkey: tag[1] };
|
|
85
|
-
if (tag[2])
|
|
86
|
-
pointer.relays =
|
|
115
|
+
if (tag[2] && isSafeRelayURL(tag[2]))
|
|
116
|
+
pointer.relays = [tag[2]];
|
|
87
117
|
return pointer;
|
|
88
118
|
}
|
|
119
|
+
/** Parses "e", "a", "p", and "q" tags into a pointer */
|
|
89
120
|
export function getPointerFromTag(tag) {
|
|
90
121
|
try {
|
|
91
122
|
switch (tag[0]) {
|
|
92
123
|
case "e":
|
|
93
|
-
return { type: "nevent", data:
|
|
124
|
+
return { type: "nevent", data: getEventPointerFromETag(tag) };
|
|
94
125
|
case "a":
|
|
95
126
|
return {
|
|
96
127
|
type: "naddr",
|
|
97
|
-
data:
|
|
128
|
+
data: getAddressPointerFromATag(tag),
|
|
98
129
|
};
|
|
99
130
|
case "p":
|
|
100
|
-
return { type: "nprofile", data:
|
|
131
|
+
return { type: "nprofile", data: getProfilePointerFromPTag(tag) };
|
|
132
|
+
// NIP-18 quote tags
|
|
133
|
+
case "q":
|
|
134
|
+
return { type: "nevent", data: getEventPointerFromETag(tag) };
|
|
101
135
|
}
|
|
102
136
|
}
|
|
103
137
|
catch (error) { }
|
|
@@ -105,21 +139,67 @@ export function getPointerFromTag(tag) {
|
|
|
105
139
|
}
|
|
106
140
|
export function isAddressPointer(pointer) {
|
|
107
141
|
return (typeof pointer !== "string" &&
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
142
|
+
Reflect.has(pointer, "identifier") &&
|
|
143
|
+
Reflect.has(pointer, "pubkey") &&
|
|
144
|
+
Reflect.has(pointer, "kind"));
|
|
111
145
|
}
|
|
112
146
|
export function isEventPointer(pointer) {
|
|
113
|
-
return typeof pointer !== "string" &&
|
|
147
|
+
return typeof pointer !== "string" && Reflect.has(pointer, "id");
|
|
114
148
|
}
|
|
149
|
+
/** Returns the coordinate string for an AddressPointer */
|
|
115
150
|
export function getCoordinateFromAddressPointer(pointer) {
|
|
116
|
-
return
|
|
151
|
+
return pointer.kind + ":" + pointer.pubkey + ":" + pointer.identifier;
|
|
117
152
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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 = getReplaceableIdentifier(event);
|
|
161
|
+
return {
|
|
162
|
+
identifier: d,
|
|
163
|
+
kind: event.kind,
|
|
164
|
+
pubkey: event.pubkey,
|
|
165
|
+
relays,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Returns an EventPointer for an event
|
|
170
|
+
* @throws
|
|
171
|
+
*/
|
|
172
|
+
export function getEventPointerForEvent(event, relays) {
|
|
173
|
+
return {
|
|
174
|
+
id: event.id,
|
|
175
|
+
kind: event.kind,
|
|
176
|
+
author: event.pubkey,
|
|
177
|
+
relays,
|
|
178
|
+
};
|
|
122
179
|
}
|
|
123
|
-
|
|
124
|
-
|
|
180
|
+
/** Returns a pointer for a given event */
|
|
181
|
+
export function getPointerForEvent(event, relays) {
|
|
182
|
+
if (kinds.isParameterizedReplaceableKind(event.kind)) {
|
|
183
|
+
const d = getReplaceableIdentifier(event);
|
|
184
|
+
return {
|
|
185
|
+
type: "naddr",
|
|
186
|
+
data: {
|
|
187
|
+
identifier: d,
|
|
188
|
+
kind: event.kind,
|
|
189
|
+
pubkey: event.pubkey,
|
|
190
|
+
relays,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
return {
|
|
196
|
+
type: "nevent",
|
|
197
|
+
data: {
|
|
198
|
+
id: event.id,
|
|
199
|
+
kind: event.kind,
|
|
200
|
+
author: event.pubkey,
|
|
201
|
+
relays,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
125
205
|
}
|
|
@@ -2,10 +2,13 @@ import { NostrEvent } from "nostr-tools";
|
|
|
2
2
|
export declare const ProfileContentSymbol: unique symbol;
|
|
3
3
|
export type ProfileContent = {
|
|
4
4
|
name?: string;
|
|
5
|
+
/** @deprecated use name instead */
|
|
6
|
+
username?: string;
|
|
5
7
|
display_name?: string;
|
|
8
|
+
/** @deprecated use display_name instead */
|
|
6
9
|
displayName?: string;
|
|
7
10
|
about?: string;
|
|
8
|
-
/** @deprecated */
|
|
11
|
+
/** @deprecated use picture instead */
|
|
9
12
|
image?: string;
|
|
10
13
|
picture?: string;
|
|
11
14
|
banner?: string;
|
|
@@ -18,3 +21,5 @@ export type ProfileContent = {
|
|
|
18
21
|
export declare function getProfileContent(event: NostrEvent): ProfileContent;
|
|
19
22
|
/** Checks if the content of the kind 0 event is valid JSON */
|
|
20
23
|
export declare function isValidProfile(profile?: NostrEvent): boolean;
|
|
24
|
+
/** Gets the display name from a profile with fallbacks */
|
|
25
|
+
export declare function getDisplayName(metadata?: ProfileContent): string | undefined;
|
package/dist/helpers/profile.js
CHANGED
|
@@ -9,7 +9,7 @@ export function getProfileContent(event) {
|
|
|
9
9
|
if (profile.nip05 && typeof profile.nip05 !== "string")
|
|
10
10
|
profile.nip05 = String(profile.nip05);
|
|
11
11
|
// add missing protocol to website
|
|
12
|
-
if (profile.website?.startsWith("http") === false) {
|
|
12
|
+
if (profile.website && profile.website?.length > 0 && profile.website?.startsWith("http") === false) {
|
|
13
13
|
profile.website = "https://" + profile.website;
|
|
14
14
|
}
|
|
15
15
|
return profile;
|
|
@@ -29,3 +29,7 @@ export function isValidProfile(profile) {
|
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
/** Gets the display name from a profile with fallbacks */
|
|
33
|
+
export function getDisplayName(metadata) {
|
|
34
|
+
return metadata?.display_name || metadata?.displayName || metadata?.name;
|
|
35
|
+
}
|
package/dist/helpers/relays.d.ts
CHANGED
|
@@ -5,8 +5,11 @@ declare module "nostr-tools" {
|
|
|
5
5
|
[SeenRelaysSymbol]?: Set<string>;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
+
/** Marks an event as being seen on a relay */
|
|
8
9
|
export declare function addSeenRelay(event: NostrEvent, relay: string): Set<string>;
|
|
10
|
+
/** Returns the set of relays this event was seen on */
|
|
9
11
|
export declare function getSeenRelays(event: NostrEvent): Set<string> | undefined;
|
|
10
|
-
|
|
11
|
-
export declare function
|
|
12
|
-
|
|
12
|
+
/** A fast check to make sure relay hints are safe to connect to */
|
|
13
|
+
export declare function isSafeRelayURL(relay: string): boolean;
|
|
14
|
+
/** Merge multiple sets of relays and remove duplicates (ignores invalid URLs) */
|
|
15
|
+
export declare function mergeRelaySets(...sources: (Iterable<string> | undefined)[]): string[];
|
package/dist/helpers/relays.js
CHANGED
|
@@ -1,31 +1,38 @@
|
|
|
1
|
+
import { normalizeURL } from "./url.js";
|
|
1
2
|
export const SeenRelaysSymbol = Symbol.for("seen-relays");
|
|
2
|
-
|
|
3
|
+
/** Marks an event as being seen on a relay */
|
|
3
4
|
export function addSeenRelay(event, relay) {
|
|
4
5
|
if (!event[SeenRelaysSymbol])
|
|
5
6
|
event[SeenRelaysSymbol] = new Set();
|
|
6
7
|
event[SeenRelaysSymbol].add(relay);
|
|
7
8
|
return event[SeenRelaysSymbol];
|
|
8
9
|
}
|
|
10
|
+
/** Returns the set of relays this event was seen on */
|
|
9
11
|
export function getSeenRelays(event) {
|
|
10
12
|
return event[SeenRelaysSymbol];
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (url.protocol !== "wss:" && url.protocol !== "ws:")
|
|
18
|
-
throw new Error("Incorrect protocol");
|
|
19
|
-
return url;
|
|
14
|
+
const WEBSOCKET_URL_CHECK = /^wss?:\/\/([-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}|localhost)\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*)$/;
|
|
15
|
+
/** A fast check to make sure relay hints are safe to connect to */
|
|
16
|
+
export function isSafeRelayURL(relay) {
|
|
17
|
+
// anything smaller than 8 is not a URL
|
|
18
|
+
return relay.length >= 8 && WEBSOCKET_URL_CHECK.test(relay);
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
/** Merge multiple sets of relays and remove duplicates (ignores invalid URLs) */
|
|
21
|
+
export function mergeRelaySets(...sources) {
|
|
22
|
+
const set = new Set();
|
|
23
|
+
for (const src of sources) {
|
|
24
|
+
if (!src)
|
|
25
|
+
continue;
|
|
26
|
+
for (const url of src) {
|
|
27
|
+
try {
|
|
28
|
+
const safe = normalizeURL(url).toString();
|
|
29
|
+
if (safe)
|
|
30
|
+
set.add(safe);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// failed to parse URL, ignore
|
|
34
|
+
}
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
|
-
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export function safeRelayUrls(urls) {
|
|
30
|
-
return Array.from(urls).map(safeRelayUrl).filter(Boolean);
|
|
37
|
+
return Array.from(set);
|
|
31
38
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { safeParse } from "./json.js";
|
|
2
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
|
+
export const SharedEventSymbol = Symbol.for("shared-event");
|
|
4
|
+
/** Returns the stringified event in the content of a kind 6 or 16 share event */
|
|
5
|
+
export function parseSharedEvent(event) {
|
|
6
|
+
return getOrComputeCachedValue(event, SharedEventSymbol, () => {
|
|
7
|
+
const json = safeParse(event.content);
|
|
8
|
+
if (!json)
|
|
9
|
+
return;
|
|
10
|
+
return json;
|
|
11
|
+
});
|
|
12
|
+
}
|
package/dist/helpers/string.d.ts
CHANGED
|
@@ -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;
|
package/dist/helpers/string.js
CHANGED
|
@@ -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;
|
package/dist/helpers/tags.d.ts
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
|
+
/** A tag with at least two indexes, the first being the name, the second the value */
|
|
2
|
+
export type NameValueTag<Name extends string = string> = [Name, string, ...string[]];
|
|
3
|
+
/** Tests if a tag has at least two indexes, and optionally the value of the first */
|
|
4
|
+
export declare function isNameValueTag<Name extends string>(tag: string[], name?: Name): tag is NameValueTag<Name>;
|
|
5
|
+
/** Checks if tag is an "e" tag and has at least one value */
|
|
1
6
|
export declare function isETag(tag: string[]): tag is ["e", string, ...string[]];
|
|
7
|
+
/** Checks if tag is an "p" tag and has at least one value */
|
|
2
8
|
export declare function isPTag(tag: string[]): tag is ["p", string, ...string[]];
|
|
9
|
+
/** Checks if tag is an "r" tag and has at least one value */
|
|
3
10
|
export declare function isRTag(tag: string[]): tag is ["r", string, ...string[]];
|
|
11
|
+
/** Checks if tag is an "d" tag and has at least one value */
|
|
4
12
|
export declare function isDTag(tag: string[]): tag is ["d", string, ...string[]];
|
|
13
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
5
14
|
export declare function isATag(tag: string[]): tag is ["a", string, ...string[]];
|
|
15
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
6
16
|
export declare function isTTag(tag: string[]): tag is ["t", string, ...string[]];
|
|
17
|
+
/** A pipeline that filters and maps each tag */
|
|
18
|
+
type TagPipe = {
|
|
19
|
+
<A>(tags: string[][], ta: (tag: string[]) => A | undefined): A[];
|
|
20
|
+
<A, B>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined): B[];
|
|
21
|
+
<A, B, C>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined): C[];
|
|
22
|
+
<A, B, C, D>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined): D[];
|
|
23
|
+
<A, B, C, D, E>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined): E[];
|
|
24
|
+
<A, B, C, D, E, F>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined, ef: (e: E) => F | undefined): F[];
|
|
25
|
+
<A, B, C, D, E, F, G>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined, ef: (e: E) => F | undefined, fg: (f: F) => G | undefined): G[];
|
|
26
|
+
};
|
|
27
|
+
/** Filter and transform tags */
|
|
28
|
+
export declare const processTags: TagPipe;
|
|
29
|
+
export {};
|
package/dist/helpers/tags.js
CHANGED
|
@@ -1,18 +1,46 @@
|
|
|
1
|
+
/** Tests if a tag has at least two indexes, and optionally the value of the first */
|
|
2
|
+
export function isNameValueTag(tag, name) {
|
|
3
|
+
return tag[0] !== undefined && tag[1] !== undefined && (name ? tag[0] === name : true);
|
|
4
|
+
}
|
|
5
|
+
/** Checks if tag is an "e" tag and has at least one value */
|
|
1
6
|
export function isETag(tag) {
|
|
2
|
-
return tag
|
|
7
|
+
return isNameValueTag(tag, "e");
|
|
3
8
|
}
|
|
9
|
+
/** Checks if tag is an "p" tag and has at least one value */
|
|
4
10
|
export function isPTag(tag) {
|
|
5
|
-
return tag
|
|
11
|
+
return isNameValueTag(tag, "p");
|
|
6
12
|
}
|
|
13
|
+
/** Checks if tag is an "r" tag and has at least one value */
|
|
7
14
|
export function isRTag(tag) {
|
|
8
|
-
return tag
|
|
15
|
+
return isNameValueTag(tag, "r");
|
|
9
16
|
}
|
|
17
|
+
/** Checks if tag is an "d" tag and has at least one value */
|
|
10
18
|
export function isDTag(tag) {
|
|
11
|
-
return tag
|
|
19
|
+
return isNameValueTag(tag, "d");
|
|
12
20
|
}
|
|
21
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
13
22
|
export function isATag(tag) {
|
|
14
|
-
return tag
|
|
23
|
+
return isNameValueTag(tag, "a");
|
|
15
24
|
}
|
|
25
|
+
/** Checks if tag is an "a" tag and has at least one value */
|
|
16
26
|
export function isTTag(tag) {
|
|
17
|
-
return tag
|
|
27
|
+
return isNameValueTag(tag, "t");
|
|
18
28
|
}
|
|
29
|
+
/** Filter and transform tags */
|
|
30
|
+
export const processTags = (tags, ...fns) => {
|
|
31
|
+
return fns.reduce((step, fn) => {
|
|
32
|
+
const next = [];
|
|
33
|
+
for (const value of step) {
|
|
34
|
+
try {
|
|
35
|
+
const result = fn(value);
|
|
36
|
+
if (result === undefined)
|
|
37
|
+
continue; // value is undefined, ignore
|
|
38
|
+
next.push(result);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// failed to process value, ignore
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return next;
|
|
45
|
+
}, tags);
|
|
46
|
+
};
|
|
@@ -23,13 +23,13 @@ export type ThreadReferences = {
|
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
25
|
export declare const Nip10ThreadRefsSymbol: unique symbol;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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(
|
|
32
|
+
export declare function interpretThreadTags(tags: string[][]): {
|
|
33
33
|
root?: {
|
|
34
34
|
e: string[];
|
|
35
35
|
a: undefined;
|