fix eslint warnings

This commit is contained in:
ennmichael
2023-02-07 20:47:57 +01:00
committed by Kieran
parent 61e6876c6d
commit 441983b8ae
89 changed files with 1018 additions and 588 deletions

View File

@ -1,12 +1,13 @@
import { useSelector } from "react-redux";
import { TaggedRawEvent } from "Nostr";
import { System } from "Nostr/System";
import { default as NEvent } from "Nostr/Event";
import EventKind from "Nostr/EventKind";
import Tag from "Nostr/Tag";
import { RootState } from "State/Store";
import { HexKey, RawEvent, u256, UserMetadata, Lists } from "Nostr";
import { bech32ToHex } from "Util";
import { bech32ToHex, unwrap } from "Util";
import { DefaultRelays, HashtagRegex } from "Const";
import { RelaySettings } from "Nostr/Connection";
@ -40,9 +41,12 @@ export default function useEventPublisher() {
async function signEvent(ev: NEvent): Promise<NEvent> {
if (hasNip07 && !privKey) {
ev.Id = await ev.CreateId();
let tmpEv = await barierNip07(() =>
const tmpEv = (await barrierNip07(() =>
window.nostr.signEvent(ev.ToObject())
);
)) as TaggedRawEvent;
if (!tmpEv.relays) {
tmpEv.relays = [];
}
return new NEvent(tmpEv);
} else if (privKey) {
await ev.Sign(privKey);
@ -111,14 +115,14 @@ export default function useEventPublisher() {
*/
broadcastForBootstrap: (ev: NEvent | undefined) => {
if (ev) {
for (let [k, _] of DefaultRelays) {
for (const [k] of DefaultRelays) {
System.WriteOnceToRelay(k, ev);
}
}
},
muted: async (keys: HexKey[], priv: HexKey[]) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.Lists;
ev.Tags.push(new Tag(["d", Lists.Muted], ev.Tags.length));
keys.forEach((p) => {
@ -129,7 +133,7 @@ export default function useEventPublisher() {
const ps = priv.map((p) => ["p", p]);
const plaintext = JSON.stringify(ps);
if (hasNip07 && !privKey) {
content = await barierNip07(() =>
content = await barrierNip07(() =>
window.nostr.nip04.encrypt(pubKey, plaintext)
);
} else if (privKey) {
@ -142,7 +146,7 @@ export default function useEventPublisher() {
},
metadata: async (obj: UserMetadata) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.SetMetadata;
ev.Content = JSON.stringify(obj);
return await signEvent(ev);
@ -150,7 +154,7 @@ export default function useEventPublisher() {
},
note: async (msg: string) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.TextNote;
processContent(ev, msg);
return await signEvent(ev);
@ -158,18 +162,14 @@ export default function useEventPublisher() {
},
zap: async (author: HexKey, note?: HexKey, msg?: string) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.ZapRequest;
if (note) {
// @ts-ignore
ev.Tags.push(new Tag(["e", note]));
ev.Tags.push(new Tag(["e", note], 0));
}
// @ts-ignore
ev.Tags.push(new Tag(["p", author]));
// @ts-ignore
ev.Tags.push(new Tag(["p", author], 0));
const relayTag = ["relays", ...Object.keys(relays).slice(0, 10)];
// @ts-ignore
ev.Tags.push(new Tag(relayTag));
ev.Tags.push(new Tag(relayTag, 0));
processContent(ev, msg || "");
return await signEvent(ev);
}
@ -179,15 +179,20 @@ export default function useEventPublisher() {
*/
reply: async (replyTo: NEvent, msg: string) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.TextNote;
let thread = replyTo.Thread;
const thread = replyTo.Thread;
if (thread) {
if (thread.Root || thread.ReplyTo) {
ev.Tags.push(
new Tag(
["e", thread.Root?.Event ?? thread.ReplyTo?.Event!, "", "root"],
[
"e",
thread.Root?.Event ?? thread.ReplyTo?.Event ?? "",
"",
"root",
],
ev.Tags.length
)
);
@ -199,7 +204,7 @@ export default function useEventPublisher() {
ev.Tags.push(new Tag(["p", replyTo.PubKey], ev.Tags.length));
}
for (let pk of thread.PubKeys) {
for (const pk of thread.PubKeys) {
if (pk === pubKey) {
continue; // dont tag self in replies
}
@ -218,7 +223,7 @@ export default function useEventPublisher() {
},
react: async (evRef: NEvent, content = "+") => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.Reaction;
ev.Content = content;
ev.Tags.push(new Tag(["e", evRef.Id], 0));
@ -228,10 +233,10 @@ export default function useEventPublisher() {
},
saveRelays: async () => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.ContactList;
ev.Content = JSON.stringify(relays);
for (let pk of follows) {
for (const pk of follows) {
ev.Tags.push(new Tag(["p", pk], ev.Tags.length));
}
@ -243,16 +248,16 @@ export default function useEventPublisher() {
newRelays?: Record<string, RelaySettings>
) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.ContactList;
ev.Content = JSON.stringify(newRelays ?? relays);
let temp = new Set(follows);
const temp = new Set(follows);
if (Array.isArray(pkAdd)) {
pkAdd.forEach((a) => temp.add(a));
} else {
temp.add(pkAdd);
}
for (let pk of temp) {
for (const pk of temp) {
if (pk.length !== 64) {
continue;
}
@ -264,10 +269,10 @@ export default function useEventPublisher() {
},
removeFollow: async (pkRemove: HexKey) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.ContactList;
ev.Content = JSON.stringify(relays);
for (let pk of follows) {
for (const pk of follows) {
if (pk === pkRemove || pk.length !== 64) {
continue;
}
@ -282,7 +287,7 @@ export default function useEventPublisher() {
*/
delete: async (id: u256) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.Deletion;
ev.Content = "";
ev.Tags.push(new Tag(["e", id], 0));
@ -290,11 +295,11 @@ export default function useEventPublisher() {
}
},
/**
* Respot a note (NIP-18)
* Repost a note (NIP-18)
*/
repost: async (note: NEvent) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.Repost;
ev.Content = JSON.stringify(note.Original);
ev.Tags.push(new Tag(["e", note.Id], 0));
@ -311,12 +316,12 @@ export default function useEventPublisher() {
return "<CANT DECRYPT>";
}
try {
let otherPubKey =
const otherPubKey =
note.PubKey === pubKey
? note.Tags.filter((a) => a.Key === "p")[0].PubKey!
? unwrap(note.Tags.filter((a) => a.Key === "p")[0].PubKey)
: note.PubKey;
if (hasNip07 && !privKey) {
return await barierNip07(() =>
return await barrierNip07(() =>
window.nostr.nip04.decrypt(otherPubKey, note.Content)
);
} else if (privKey) {
@ -324,21 +329,21 @@ export default function useEventPublisher() {
return note.Content;
}
} catch (e) {
console.error("Decyrption failed", e);
console.error("Decryption failed", e);
return "<DECRYPTION FAILED>";
}
}
},
sendDm: async (content: string, to: HexKey) => {
if (pubKey) {
let ev = NEvent.ForPubKey(pubKey);
const ev = NEvent.ForPubKey(pubKey);
ev.Kind = EventKind.DirectMessage;
ev.Content = content;
ev.Tags.push(new Tag(["p", to], 0));
try {
if (hasNip07 && !privKey) {
let cx: string = await barierNip07(() =>
const cx: string = await barrierNip07(() =>
window.nostr.nip04.encrypt(to, content)
);
ev.Content = cx;
@ -358,12 +363,12 @@ export default function useEventPublisher() {
let isNip07Busy = false;
const delay = (t: number) => {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
setTimeout(resolve, t);
});
};
export const barierNip07 = async (then: () => Promise<any>) => {
export const barrierNip07 = async <T>(then: () => Promise<T>): Promise<T> => {
while (isNip07Busy) {
await delay(10);
}

View File

@ -6,7 +6,7 @@ import useSubscription from "Feed/Subscription";
export default function useFollowersFeed(pubkey: HexKey) {
const sub = useMemo(() => {
let x = new Subscriptions();
const x = new Subscriptions();
x.Id = `followers:${pubkey.slice(0, 12)}`;
x.Kinds = new Set([EventKind.ContactList]);
x.PTags = new Set([pubkey]);

View File

@ -6,7 +6,7 @@ import useSubscription, { NoteStore } from "Feed/Subscription";
export default function useFollowsFeed(pubkey: HexKey) {
const sub = useMemo(() => {
let x = new Subscriptions();
const x = new Subscriptions();
x.Id = `follows:${pubkey.slice(0, 12)}`;
x.Kinds = new Set([EventKind.ContactList]);
x.Authors = new Set([pubkey]);
@ -18,10 +18,10 @@ export default function useFollowsFeed(pubkey: HexKey) {
}
export function getFollowers(feed: NoteStore, pubkey: HexKey) {
let contactLists = feed?.notes.filter(
const contactLists = feed?.notes.filter(
(a) => a.kind === EventKind.ContactList && a.pubkey === pubkey
);
let pTags = contactLists?.map((a) =>
const pTags = contactLists?.map((a) =>
a.tags.filter((b) => b[0] === "p").map((c) => c[1])
);
return [...new Set(pTags?.flat())];

View File

@ -2,6 +2,7 @@ import * as secp from "@noble/secp256k1";
import * as base64 from "@protobufjs/base64";
import { useSelector } from "react-redux";
import { RootState } from "State/Store";
import { unwrap } from "Util";
export interface ImgProxySettings {
url: string;
@ -21,8 +22,8 @@ export default function useImgProxy() {
async function signUrl(u: string) {
const result = await secp.utils.hmacSha256(
secp.utils.hexToBytes(settings!.key),
secp.utils.hexToBytes(settings!.salt),
secp.utils.hexToBytes(unwrap(settings).key),
secp.utils.hexToBytes(unwrap(settings).salt),
te.encode(u)
);
return urlSafe(base64.encode(result, 0, result.byteLength));

View File

@ -19,9 +19,10 @@ import { RootState } from "State/Store";
import { mapEventToProfile, MetadataCache } from "State/Users";
import { useDb } from "State/Users/Db";
import useSubscription from "Feed/Subscription";
import { barierNip07 } from "Feed/EventPublisher";
import { barrierNip07 } from "Feed/EventPublisher";
import { getMutedKeys, getNewest } from "Feed/MuteList";
import useModeration from "Hooks/useModeration";
import { unwrap } from "Util";
/**
* Managed loading data for the current logged in user
@ -40,7 +41,7 @@ export default function useLoginFeed() {
const subMetadata = useMemo(() => {
if (!pubKey) return null;
let sub = new Subscriptions();
const sub = new Subscriptions();
sub.Id = `login:meta`;
sub.Authors = new Set([pubKey]);
sub.Kinds = new Set([EventKind.ContactList, EventKind.SetMetadata]);
@ -52,7 +53,7 @@ export default function useLoginFeed() {
const subNotification = useMemo(() => {
if (!pubKey) return null;
let sub = new Subscriptions();
const sub = new Subscriptions();
sub.Id = "login:notifications";
// todo: add zaps
sub.Kinds = new Set([EventKind.TextNote]);
@ -64,7 +65,7 @@ export default function useLoginFeed() {
const subMuted = useMemo(() => {
if (!pubKey) return null;
let sub = new Subscriptions();
const sub = new Subscriptions();
sub.Id = "login:muted";
sub.Kinds = new Set([EventKind.Lists]);
sub.Authors = new Set([pubKey]);
@ -77,12 +78,12 @@ export default function useLoginFeed() {
const subDms = useMemo(() => {
if (!pubKey) return null;
let dms = new Subscriptions();
const dms = new Subscriptions();
dms.Id = "login:dms";
dms.Kinds = new Set([EventKind.DirectMessage]);
dms.PTags = new Set([pubKey]);
let dmsFromME = new Subscriptions();
const dmsFromME = new Subscriptions();
dmsFromME.Authors = new Set([pubKey]);
dmsFromME.Kinds = new Set([EventKind.DirectMessage]);
dms.AddSubscription(dmsFromME);
@ -102,28 +103,28 @@ export default function useLoginFeed() {
const mutedFeed = useSubscription(subMuted, { leaveOpen: true, cache: true });
useEffect(() => {
let contactList = metadataFeed.store.notes.filter(
const contactList = metadataFeed.store.notes.filter(
(a) => a.kind === EventKind.ContactList
);
let metadata = metadataFeed.store.notes.filter(
const metadata = metadataFeed.store.notes.filter(
(a) => a.kind === EventKind.SetMetadata
);
let profiles = metadata
const profiles = metadata
.map((a) => mapEventToProfile(a))
.filter((a) => a !== undefined)
.map((a) => a!);
.map((a) => unwrap(a));
for (let cl of contactList) {
for (const cl of contactList) {
if (cl.content !== "" && cl.content !== "{}") {
let relays = JSON.parse(cl.content);
const relays = JSON.parse(cl.content);
dispatch(setRelays({ relays, createdAt: cl.created_at }));
}
let pTags = cl.tags.filter((a) => a[0] === "p").map((a) => a[1]);
const pTags = cl.tags.filter((a) => a[0] === "p").map((a) => a[1]);
dispatch(setFollows({ keys: pTags, createdAt: cl.created_at }));
}
(async () => {
let maxProfile = profiles.reduce(
const maxProfile = profiles.reduce(
(acc, v) => {
if (v.created > acc.created) {
acc.profile = v;
@ -134,7 +135,7 @@ export default function useLoginFeed() {
{ created: 0, profile: null as MetadataCache | null }
);
if (maxProfile.profile) {
let existing = await db.find(maxProfile.profile.pubkey);
const existing = await db.find(maxProfile.profile.pubkey);
if ((existing?.created ?? 0) < maxProfile.created) {
await db.put(maxProfile.profile);
}
@ -153,7 +154,7 @@ export default function useLoginFeed() {
dispatch(setLatestNotifications(nx.created_at));
makeNotification(db, nx).then((notification) => {
if (notification) {
// @ts-ignore
// @ts-expect-error This is typed wrong, but I don't have the time to fix it right now
dispatch(sendNotification(notification));
}
});
@ -176,8 +177,8 @@ export default function useLoginFeed() {
try {
const blocked = JSON.parse(plaintext);
const keys = blocked
.filter((p: any) => p && p.length === 2 && p[0] === "p")
.map((p: any) => p[1]);
.filter((p: string) => p && p.length === 2 && p[0] === "p")
.map((p: string) => p[1]);
dispatch(
setBlocked({
keys,
@ -193,7 +194,7 @@ export default function useLoginFeed() {
}, [dispatch, mutedFeed.store]);
useEffect(() => {
let dms = dmsFeed.store.notes.filter(
const dms = dmsFeed.store.notes.filter(
(a) => a.kind === EventKind.DirectMessage
);
dispatch(addDirectMessage(dms));
@ -209,7 +210,7 @@ async function decryptBlocked(
if (pubKey && privKey) {
return await ev.DecryptData(raw.content, privKey, pubKey);
} else {
return await barierNip07(() =>
return await barrierNip07(() =>
window.nostr.nip04.decrypt(pubKey, raw.content)
);
}

View File

@ -7,7 +7,7 @@ import useSubscription, { NoteStore } from "Feed/Subscription";
export default function useMutedFeed(pubkey: HexKey) {
const sub = useMemo(() => {
let sub = new Subscriptions();
const sub = new Subscriptions();
sub.Id = `muted:${pubkey.slice(0, 12)}`;
sub.Kinds = new Set([EventKind.Lists]);
sub.Authors = new Set([pubkey]);
@ -44,7 +44,7 @@ export function getMutedKeys(rawNotes: TaggedRawEvent[]): {
}
export function getMuted(feed: NoteStore, pubkey: HexKey): HexKey[] {
let lists = feed?.notes.filter(
const lists = feed?.notes.filter(
(a) => a.kind === EventKind.Lists && a.pubkey === pubkey
);
return getMutedKeys(lists).keys;

View File

@ -1,16 +1,16 @@
import { useSyncExternalStore } from "react";
import { System } from "Nostr/System";
import { CustomHook, StateSnapshot } from "Nostr/Connection";
import { StateSnapshot } from "Nostr/Connection";
const noop = (f: CustomHook) => {
return () => {};
const noop = () => {
return () => undefined;
};
const noopState = (): StateSnapshot | undefined => {
return undefined;
};
export default function useRelayState(addr: string) {
let c = System.Sockets.get(addr);
const c = System.Sockets.get(addr);
return useSyncExternalStore<StateSnapshot | undefined>(
c?.StatusHook.bind(c) ?? noop,
c?.GetState.bind(c) ?? noopState

View File

@ -2,7 +2,7 @@ import { useEffect, useMemo, useReducer, useState } from "react";
import { System } from "Nostr/System";
import { TaggedRawEvent } from "Nostr";
import { Subscriptions } from "Nostr/Subscriptions";
import { debounce } from "Util";
import { debounce, unwrap } from "Util";
import { db } from "Db";
export type NoteStore = {
@ -17,7 +17,7 @@ export type UseSubscriptionOptions = {
interface ReducerArg {
type: "END" | "EVENT" | "CLEAR";
ev?: TaggedRawEvent | Array<TaggedRawEvent>;
ev?: TaggedRawEvent | TaggedRawEvent[];
end?: boolean;
}
@ -25,7 +25,7 @@ function notesReducer(state: NoteStore, arg: ReducerArg) {
if (arg.type === "END") {
return {
notes: state.notes,
end: arg.end!,
end: arg.end ?? false,
} as NoteStore;
}
@ -36,11 +36,11 @@ function notesReducer(state: NoteStore, arg: ReducerArg) {
} as NoteStore;
}
let evs = arg.ev!;
if (!Array.isArray(evs)) {
evs = [evs];
let evs = arg.ev;
if (!(evs instanceof Array)) {
evs = evs === undefined ? [] : [evs];
}
let existingIds = new Set(state.notes.map((a) => a.id));
const existingIds = new Set(state.notes.map((a) => a.id));
evs = evs.filter((a) => !existingIds.has(a.id));
if (evs.length === 0) {
return state;
@ -175,7 +175,7 @@ const PreloadNotes = async (id: string): Promise<TaggedRawEvent[]> => {
const feed = await db.feeds.get(id);
if (feed) {
const events = await db.events.bulkGet(feed.ids);
return events.filter((a) => a !== undefined).map((a) => a!);
return events.filter((a) => a !== undefined).map((a) => unwrap(a));
}
return [];
};

View File

@ -16,9 +16,9 @@ export default function useThreadFeed(id: u256) {
function addId(id: u256[]) {
setTrackingEvent((s) => {
let orig = new Set(s);
const orig = new Set(s);
if (id.some((a) => !orig.has(a))) {
let tmp = new Set([...s, ...id]);
const tmp = new Set([...s, ...id]);
return Array.from(tmp);
} else {
return s;
@ -55,16 +55,16 @@ export default function useThreadFeed(id: u256) {
useEffect(() => {
if (main.store) {
return debounce(200, () => {
let mainNotes = main.store.notes.filter(
const mainNotes = main.store.notes.filter(
(a) => a.kind === EventKind.TextNote
);
let eTags = mainNotes
const eTags = mainNotes
.filter((a) => a.kind === EventKind.TextNote)
.map((a) => a.tags.filter((b) => b[0] === "e").map((b) => b[1]))
.flat();
let ids = mainNotes.map((a) => a.id);
let allEvents = new Set([...eTags, ...ids]);
const ids = mainNotes.map((a) => a.id);
const allEvents = new Set([...eTags, ...ids]);
addId(Array.from(allEvents));
});
}

View File

@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import { u256 } from "Nostr";
import EventKind from "Nostr/EventKind";
import { Subscriptions } from "Nostr/Subscriptions";
import { unixNow } from "Util";
import { unixNow, unwrap } from "Util";
import useSubscription from "Feed/Subscription";
import { useSelector } from "react-redux";
import { RootState } from "State/Store";
@ -38,7 +38,7 @@ export default function useTimelineFeed(
return null;
}
let sub = new Subscriptions();
const sub = new Subscriptions();
sub.Id = `timeline:${subject.type}:${subject.discriminator}`;
sub.Kinds = new Set([EventKind.TextNote, EventKind.Repost]);
switch (subject.type) {
@ -64,7 +64,7 @@ export default function useTimelineFeed(
}, [subject.type, subject.items, subject.discriminator]);
const sub = useMemo(() => {
let sub = createSub();
const sub = createSub();
if (sub) {
if (options.method === "LIMIT_UNTIL") {
sub.Until = until;
@ -80,7 +80,7 @@ export default function useTimelineFeed(
if (pref.autoShowLatest) {
// copy properties of main sub but with limit 0
// this will put latest directly into main feed
let latestSub = new Subscriptions();
const latestSub = new Subscriptions();
latestSub.Authors = sub.Authors;
latestSub.HashTags = sub.HashTags;
latestSub.PTags = sub.PTags;
@ -97,7 +97,7 @@ export default function useTimelineFeed(
const main = useSubscription(sub, { leaveOpen: true, cache: true });
const subRealtime = useMemo(() => {
let subLatest = createSub();
const subLatest = createSub();
if (subLatest && !pref.autoShowLatest) {
subLatest.Id = `${subLatest.Id}:latest`;
subLatest.Limit = 1;
@ -131,7 +131,7 @@ export default function useTimelineFeed(
const subParents = useMemo(() => {
if (trackingParentEvents.length > 0) {
let parents = new Subscriptions();
const parents = new Subscriptions();
parents.Id = `timeline-parent:${subject.type}`;
parents.Ids = new Set(trackingParentEvents);
return parents;
@ -144,21 +144,21 @@ export default function useTimelineFeed(
useEffect(() => {
if (main.store.notes.length > 0) {
setTrackingEvent((s) => {
let ids = main.store.notes.map((a) => a.id);
const ids = main.store.notes.map((a) => a.id);
if (ids.some((a) => !s.includes(a))) {
return Array.from(new Set([...s, ...ids]));
}
return s;
});
let reposts = main.store.notes
const reposts = main.store.notes
.filter((a) => a.kind === EventKind.Repost && a.content === "")
.map((a) => a.tags.find((b) => b[0] === "e"))
.filter((a) => a)
.map((a) => a![1]);
.map((a) => unwrap(a)[1]);
if (reposts.length > 0) {
setTrackingParentEvents((s) => {
if (reposts.some((a) => !s.includes(a))) {
let temp = new Set([...s, ...reposts]);
const temp = new Set([...s, ...reposts]);
return Array.from(temp);
}
return s;
@ -175,7 +175,7 @@ export default function useTimelineFeed(
loadMore: () => {
console.debug("Timeline load more!");
if (options.method === "LIMIT_UNTIL") {
let oldest = main.store.notes.reduce(
const oldest = main.store.notes.reduce(
(acc, v) => (acc = v.created_at < acc ? v.created_at : acc),
unixNow()
);

View File

@ -6,7 +6,7 @@ import useSubscription from "./Subscription";
export default function useZapsFeed(pubkey: HexKey) {
const sub = useMemo(() => {
let x = new Subscriptions();
const x = new Subscriptions();
x.Id = `zaps:${pubkey.slice(0, 12)}`;
x.Kinds = new Set([EventKind.ZapReceipt]);
x.PTags = new Set([pubkey]);