applesauce-core 0.9.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.
- package/README.md +1 -1
- package/dist/event-store/database.d.ts +17 -13
- package/dist/event-store/database.js +50 -33
- package/dist/event-store/event-store.d.ts +37 -14
- package/dist/event-store/event-store.js +249 -96
- package/dist/helpers/bolt11.d.ts +1 -0
- package/dist/helpers/bolt11.js +1 -0
- package/dist/helpers/comment.d.ts +48 -0
- package/dist/helpers/comment.js +116 -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/emoji.d.ts +10 -1
- package/dist/helpers/emoji.js +12 -0
- package/dist/helpers/event.d.ts +9 -1
- package/dist/helpers/event.js +25 -1
- package/dist/helpers/external-id.d.ts +29 -0
- package/dist/helpers/external-id.js +20 -0
- package/dist/helpers/filter.d.ts +0 -2
- package/dist/helpers/filter.js +3 -7
- package/dist/helpers/hidden-tags.d.ts +48 -0
- package/dist/helpers/hidden-tags.js +108 -0
- package/dist/helpers/hidden-tags.test.d.ts +1 -0
- package/dist/helpers/hidden-tags.test.js +28 -0
- package/dist/helpers/index.d.ts +16 -8
- package/dist/helpers/index.js +16 -8
- package/dist/helpers/json.d.ts +1 -0
- package/dist/helpers/json.js +1 -0
- package/dist/helpers/lnurl.d.ts +4 -0
- package/dist/helpers/lnurl.js +40 -0
- package/dist/helpers/mailboxes.test.js +13 -12
- package/dist/helpers/media-attachment.d.ts +33 -0
- package/dist/helpers/media-attachment.js +60 -0
- package/dist/helpers/pointers.d.ts +38 -5
- package/dist/helpers/pointers.js +101 -17
- package/dist/helpers/profile.js +1 -1
- package/dist/helpers/string.d.ts +6 -0
- package/dist/helpers/string.js +2 -0
- package/dist/helpers/tags.d.ts +6 -0
- package/dist/helpers/tags.js +6 -0
- package/dist/helpers/threading.d.ts +6 -6
- package/dist/helpers/threading.js +30 -9
- package/dist/helpers/threading.test.d.ts +1 -0
- package/dist/helpers/threading.test.js +41 -0
- package/dist/helpers/url.d.ts +4 -1
- package/dist/helpers/url.js +4 -3
- package/dist/helpers/zap.d.ts +25 -0
- package/dist/helpers/zap.js +32 -3
- package/dist/observable/{getValue.d.ts → get-value.d.ts} +1 -0
- package/dist/observable/{getValue.js → get-value.js} +1 -0
- package/dist/observable/index.d.ts +1 -1
- package/dist/observable/index.js +1 -1
- package/dist/promise/deferred.d.ts +1 -0
- package/dist/promise/deferred.js +1 -0
- package/dist/queries/comments.d.ts +4 -0
- package/dist/queries/comments.js +14 -0
- package/dist/queries/index.d.ts +3 -2
- package/dist/queries/index.js +3 -2
- package/dist/queries/mailboxes.d.ts +1 -0
- package/dist/queries/mailboxes.js +1 -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 +3 -3
- package/dist/queries/simple.js +13 -13
- package/dist/queries/thread.d.ts +2 -0
- package/dist/queries/thread.js +29 -3
- package/dist/queries/zaps.d.ts +1 -0
- package/dist/queries/zaps.js +1 -0
- package/dist/query-store/index.d.ts +22 -12
- package/dist/query-store/index.js +36 -30
- package/package.json +10 -18
|
@@ -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;
|
|
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";
|
|
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":
|
|
@@ -62,7 +66,11 @@ 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] };
|
|
@@ -70,7 +78,25 @@ export function getEventPointerFromTag(tag) {
|
|
|
70
78
|
pointer.relays = safeRelayUrls([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])
|
|
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) {
|
|
74
100
|
if (!tag[1])
|
|
75
101
|
throw new Error("Missing coordinate in tag");
|
|
76
102
|
const pointer = parseCoordinate(tag[1], true, false);
|
|
@@ -78,7 +104,11 @@ export function getAddressPointerFromTag(tag) {
|
|
|
78
104
|
pointer.relays = safeRelayUrls([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] };
|
|
@@ -86,18 +116,22 @@ export function getProfilePointerFromTag(tag) {
|
|
|
86
116
|
pointer.relays = safeRelayUrls([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,71 @@ 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
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 = 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
|
+
};
|
|
122
169
|
}
|
|
123
|
-
|
|
124
|
-
|
|
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
|
+
}
|
|
125
209
|
}
|
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;
|
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,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[]];
|
package/dist/helpers/tags.js
CHANGED
|
@@ -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
|
}
|
|
@@ -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;
|
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAddressPointerFromATag } from "./pointers.js";
|
|
2
2
|
import { getOrComputeCachedValue } from "./cache.js";
|
|
3
|
+
import { safeRelayUrls } from "./relays.js";
|
|
3
4
|
export const Nip10ThreadRefsSymbol = Symbol.for("nip10-thread-refs");
|
|
5
|
+
/**
|
|
6
|
+
* Gets an EventPointer form a NIP-10 threading "e" tag
|
|
7
|
+
* @throws
|
|
8
|
+
*/
|
|
9
|
+
export function getEventPointerFromThreadTag(tag) {
|
|
10
|
+
if (!tag[1])
|
|
11
|
+
throw new Error("Missing event id in tag");
|
|
12
|
+
let pointer = { id: tag[1] };
|
|
13
|
+
if (tag[2])
|
|
14
|
+
pointer.relays = safeRelayUrls([tag[2]]);
|
|
15
|
+
// get author from NIP-18 quote tags, nip-22 comments tags, or nip-10 thread tags
|
|
16
|
+
if (tag[0] === "e" &&
|
|
17
|
+
(tag[3] === "root" || tag[3] === "reply" || tag[3] === "mention") &&
|
|
18
|
+
tag[4] &&
|
|
19
|
+
tag[4].length === 64) {
|
|
20
|
+
// NIP-10 "e" tag
|
|
21
|
+
pointer.author = tag[4];
|
|
22
|
+
}
|
|
23
|
+
return pointer;
|
|
24
|
+
}
|
|
4
25
|
/** Parses NIP-10 tags and handles legacy behavior */
|
|
5
|
-
export function interpretThreadTags(
|
|
6
|
-
const eTags =
|
|
7
|
-
const aTags =
|
|
26
|
+
export function interpretThreadTags(tags) {
|
|
27
|
+
const eTags = tags.filter((t) => t[0] === "e" && t[1]);
|
|
28
|
+
const aTags = tags.filter((t) => t[0] === "a" && t[1]);
|
|
8
29
|
// find the root and reply tags.
|
|
9
30
|
let rootETag = eTags.find((t) => t[3] === "root");
|
|
10
31
|
let replyETag = eTags.find((t) => t[3] === "reply");
|
|
@@ -44,13 +65,13 @@ export function interpretThreadTags(event) {
|
|
|
44
65
|
/** Returns the parsed NIP-10 tags for an event */
|
|
45
66
|
export function getNip10References(event) {
|
|
46
67
|
return getOrComputeCachedValue(event, Nip10ThreadRefsSymbol, () => {
|
|
47
|
-
const tags = interpretThreadTags(event);
|
|
68
|
+
const tags = interpretThreadTags(event.tags);
|
|
48
69
|
let root;
|
|
49
70
|
if (tags.root) {
|
|
50
71
|
try {
|
|
51
72
|
root = {
|
|
52
|
-
e: tags.root.e &&
|
|
53
|
-
a: tags.root.a &&
|
|
73
|
+
e: tags.root.e && getEventPointerFromThreadTag(tags.root.e),
|
|
74
|
+
a: tags.root.a && getAddressPointerFromATag(tags.root.a),
|
|
54
75
|
};
|
|
55
76
|
}
|
|
56
77
|
catch (error) { }
|
|
@@ -59,8 +80,8 @@ export function getNip10References(event) {
|
|
|
59
80
|
if (tags.reply) {
|
|
60
81
|
try {
|
|
61
82
|
reply = {
|
|
62
|
-
e: tags.reply.e &&
|
|
63
|
-
a: tags.reply.a &&
|
|
83
|
+
e: tags.reply.e && getEventPointerFromThreadTag(tags.reply.e),
|
|
84
|
+
a: tags.reply.a && getAddressPointerFromATag(tags.reply.a),
|
|
64
85
|
};
|
|
65
86
|
}
|
|
66
87
|
catch (error) { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { interpretThreadTags } from "./threading.js";
|
|
3
|
+
describe("threading helpers", () => {
|
|
4
|
+
describe("interpretThreadTags", () => {
|
|
5
|
+
it("should handle legacy tags", () => {
|
|
6
|
+
expect(interpretThreadTags([
|
|
7
|
+
["e", "root-id"],
|
|
8
|
+
["e", "reply-id"],
|
|
9
|
+
])).toEqual({ root: { a: undefined, e: ["e", "root-id"] }, reply: { a: undefined, e: ["e", "reply-id"] } });
|
|
10
|
+
});
|
|
11
|
+
it("should handle nip-10 tags", () => {
|
|
12
|
+
expect(interpretThreadTags([
|
|
13
|
+
["e", "root-id", "relay", "root"],
|
|
14
|
+
["e", "reply-id", "relay", "reply"],
|
|
15
|
+
])).toEqual({
|
|
16
|
+
root: { a: undefined, e: ["e", "root-id", "relay", "root"] },
|
|
17
|
+
reply: { a: undefined, e: ["e", "reply-id", "relay", "reply"] },
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it("should ignore mention nip-10 tags", () => {
|
|
21
|
+
expect(interpretThreadTags([
|
|
22
|
+
["e", "root-id", "relay", "root"],
|
|
23
|
+
["e", "mention-id", "relay", "mention"],
|
|
24
|
+
["e", "reply-id", "relay", "reply"],
|
|
25
|
+
])).toEqual({
|
|
26
|
+
root: { a: undefined, e: ["e", "root-id", "relay", "root"] },
|
|
27
|
+
reply: { a: undefined, e: ["e", "reply-id", "relay", "reply"] },
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
it("should handle single nip-10 tags", () => {
|
|
31
|
+
expect(interpretThreadTags([["e", "root-id", "relay", "root"]])).toEqual({
|
|
32
|
+
root: { a: undefined, e: ["e", "root-id", "relay", "root"] },
|
|
33
|
+
reply: { a: undefined, e: ["e", "root-id", "relay", "root"] },
|
|
34
|
+
});
|
|
35
|
+
expect(interpretThreadTags([["e", "reply-id", "relay", "reply"]])).toEqual({
|
|
36
|
+
root: { a: undefined, e: ["e", "reply-id", "relay", "reply"] },
|
|
37
|
+
reply: { a: undefined, e: ["e", "reply-id", "relay", "reply"] },
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
package/dist/helpers/url.d.ts
CHANGED
|
@@ -4,8 +4,11 @@ export declare const IMAGE_EXT: string[];
|
|
|
4
4
|
export declare const VIDEO_EXT: string[];
|
|
5
5
|
export declare const STREAM_EXT: string[];
|
|
6
6
|
export declare const AUDIO_EXT: string[];
|
|
7
|
-
|
|
7
|
+
/** Checks if a url is a image URL */
|
|
8
8
|
export declare function isImageURL(url: string | URL): boolean;
|
|
9
|
+
/** Checks if a url is a video URL */
|
|
9
10
|
export declare function isVideoURL(url: string | URL): boolean;
|
|
11
|
+
/** Checks if a url is a stream URL */
|
|
10
12
|
export declare function isStreamURL(url: string | URL): boolean;
|
|
13
|
+
/** Checks if a url is a audio URL */
|
|
11
14
|
export declare function isAudioURL(url: string | URL): boolean;
|
package/dist/helpers/url.js
CHANGED
|
@@ -4,24 +4,25 @@ export const IMAGE_EXT = [".svg", ".gif", ".png", ".jpg", ".jpeg", ".webp", ".av
|
|
|
4
4
|
export const VIDEO_EXT = [".mp4", ".mkv", ".webm", ".mov"];
|
|
5
5
|
export const STREAM_EXT = [".m3u8"];
|
|
6
6
|
export const AUDIO_EXT = [".mp3", ".wav", ".ogg", ".aac"];
|
|
7
|
-
|
|
8
|
-
return isImageURL(url) || isVideoURL(url) || isStreamURL(url);
|
|
9
|
-
}
|
|
7
|
+
/** Checks if a url is a image URL */
|
|
10
8
|
export function isImageURL(url) {
|
|
11
9
|
url = convertToUrl(url);
|
|
12
10
|
const filename = getURLFilename(url);
|
|
13
11
|
return !!filename && IMAGE_EXT.some((ext) => filename.endsWith(ext));
|
|
14
12
|
}
|
|
13
|
+
/** Checks if a url is a video URL */
|
|
15
14
|
export function isVideoURL(url) {
|
|
16
15
|
url = convertToUrl(url);
|
|
17
16
|
const filename = getURLFilename(url);
|
|
18
17
|
return !!filename && VIDEO_EXT.some((ext) => filename.endsWith(ext));
|
|
19
18
|
}
|
|
19
|
+
/** Checks if a url is a stream URL */
|
|
20
20
|
export function isStreamURL(url) {
|
|
21
21
|
url = convertToUrl(url);
|
|
22
22
|
const filename = getURLFilename(url);
|
|
23
23
|
return !!filename && STREAM_EXT.some((ext) => filename.endsWith(ext));
|
|
24
24
|
}
|
|
25
|
+
/** Checks if a url is a audio URL */
|
|
25
26
|
export function isAudioURL(url) {
|
|
26
27
|
url = convertToUrl(url);
|
|
27
28
|
const filename = getURLFilename(url);
|
package/dist/helpers/zap.d.ts
CHANGED
|
@@ -4,11 +4,36 @@ export declare const ZapFromSymbol: unique symbol;
|
|
|
4
4
|
export declare const ZapInvoiceSymbol: unique symbol;
|
|
5
5
|
export declare const ZapEventPointerSymbol: unique symbol;
|
|
6
6
|
export declare const ZapAddressPointerSymbol: unique symbol;
|
|
7
|
+
/** Returns the senders pubkey */
|
|
7
8
|
export declare function getZapSender(zap: NostrEvent): string;
|
|
9
|
+
/**
|
|
10
|
+
* Gets the receivers pubkey
|
|
11
|
+
* @throws
|
|
12
|
+
*/
|
|
8
13
|
export declare function getZapRecipient(zap: NostrEvent): string;
|
|
14
|
+
/** Returns the parsed bolt11 invoice */
|
|
9
15
|
export declare function getZapPayment(zap: NostrEvent): import("./bolt11.js").ParsedInvoice | undefined;
|
|
16
|
+
/** Gets the AddressPointer that was zapped */
|
|
10
17
|
export declare function getZapAddressPointer(zap: NostrEvent): import("nostr-tools/nip19").AddressPointer | null;
|
|
18
|
+
/** Gets the EventPointer that was zapped */
|
|
11
19
|
export declare function getZapEventPointer(zap: NostrEvent): import("nostr-tools/nip19").EventPointer | null;
|
|
20
|
+
/** Gets the preimage for the bolt11 invoice */
|
|
12
21
|
export declare function getZapPreimage(zap: NostrEvent): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the zap request event inside the zap receipt
|
|
24
|
+
* @throws
|
|
25
|
+
*/
|
|
13
26
|
export declare function getZapRequest(zap: NostrEvent): import("nostr-tools").Event;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if the zap is valid
|
|
29
|
+
* DOES NOT validate LNURL address
|
|
30
|
+
*/
|
|
14
31
|
export declare function isValidZap(zap?: NostrEvent): boolean;
|
|
32
|
+
export type ZapSplit = {
|
|
33
|
+
pubkey: string;
|
|
34
|
+
percent: number;
|
|
35
|
+
weight: number;
|
|
36
|
+
relay?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Returns the zap splits for an event */
|
|
39
|
+
export declare function getZapSplits(event: NostrEvent): ZapSplit[] | undefined;
|