diff --git a/packages/app/.gitignore b/packages/app/.gitignore index 3a1bea68..3486a8a6 100644 --- a/packages/app/.gitignore +++ b/packages/app/.gitignore @@ -23,3 +23,5 @@ yarn-debug.log* yarn-error.log* .idea + +dist/ diff --git a/packages/app/src/Cache/DMCache.ts b/packages/app/src/Cache/DMCache.ts index 7cbce8df..4041a0fc 100644 --- a/packages/app/src/Cache/DMCache.ts +++ b/packages/app/src/Cache/DMCache.ts @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import { db } from "Db"; import FeedCache from "./FeedCache"; diff --git a/packages/app/src/Cache/UserCache.ts b/packages/app/src/Cache/UserCache.ts index 731a7422..1b9ce04b 100644 --- a/packages/app/src/Cache/UserCache.ts +++ b/packages/app/src/Cache/UserCache.ts @@ -1,6 +1,6 @@ import FeedCache from "Cache/FeedCache"; import { db } from "Db"; -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; import { LNURL } from "LNURL"; import { fetchNip05Pubkey } from "Nip05/Verifier"; diff --git a/packages/app/src/Cache/index.ts b/packages/app/src/Cache/index.ts index 0f0cabb4..ec3f6c0f 100644 --- a/packages/app/src/Cache/index.ts +++ b/packages/app/src/Cache/index.ts @@ -1,57 +1,8 @@ -import { HexKey, NostrEvent, UserMetadata } from "System"; -import { hexToBech32, unixNowMs } from "SnortUtils"; import { DmCache } from "./DMCache"; import { InteractionCache } from "./EventInteractionCache"; import { UserCache } from "./UserCache"; import { UserRelays } from "./UserRelayCache"; -export interface MetadataCache extends UserMetadata { - /** - * When the object was saved in cache - */ - loaded: number; - - /** - * When the source metadata event was created - */ - created: number; - - /** - * The pubkey of the owner of this metadata - */ - pubkey: HexKey; - - /** - * The bech32 encoded pubkey - */ - npub: string; - - /** - * Pubkey of zapper service - */ - zapService?: HexKey; - - /** - * If the nip05 is valid for this user - */ - isNostrAddressValid: boolean; -} - -export function mapEventToProfile(ev: NostrEvent) { - try { - const data: UserMetadata = JSON.parse(ev.content); - return { - ...data, - pubkey: ev.pubkey, - npub: hexToBech32("npub", ev.pubkey), - created: ev.created_at, - loaded: unixNowMs(), - } as MetadataCache; - } catch (e) { - console.error("Failed to parse JSON", ev, e); - } -} - export async function preload(follows?: Array) { const preloads = [ UserCache.preload(follows), diff --git a/packages/app/src/Const.ts b/packages/app/src/Const.ts index e16d2262..db961bc6 100644 --- a/packages/app/src/Const.ts +++ b/packages/app/src/Const.ts @@ -1,6 +1,4 @@ -import { UserRelays } from "Cache/UserRelayCache"; -import { NostrSystem, RelaySettings } from "System"; -import { ProfileLoaderService } from "System/ProfileCache"; +import { RelaySettings } from "@snort/system"; /** * Add-on api for snort features diff --git a/packages/app/src/Db/index.ts b/packages/app/src/Db/index.ts index 9a72e8f3..cb501536 100644 --- a/packages/app/src/Db/index.ts +++ b/packages/app/src/Db/index.ts @@ -1,6 +1,5 @@ import Dexie, { Table } from "dexie"; -import { FullRelaySettings, HexKey, NostrEvent, u256 } from "System"; -import { MetadataCache } from "Cache"; +import { FullRelaySettings, HexKey, NostrEvent, u256, MetadataCache } from "@snort/system"; export const NAME = "snortDB"; export const VERSION = 8; diff --git a/packages/app/src/Element/Avatar.tsx b/packages/app/src/Element/Avatar.tsx index 576ef169..89fef4aa 100644 --- a/packages/app/src/Element/Avatar.tsx +++ b/packages/app/src/Element/Avatar.tsx @@ -2,7 +2,7 @@ import "./Avatar.css"; import Nostrich from "nostrich.webp"; import { CSSProperties, useEffect, useState } from "react"; -import type { UserMetadata } from "System"; +import type { UserMetadata } from "@snort/system"; import useImgProxy from "Hooks/useImgProxy"; diff --git a/packages/app/src/Element/BadgeList.tsx b/packages/app/src/Element/BadgeList.tsx index e007b685..36088902 100644 --- a/packages/app/src/Element/BadgeList.tsx +++ b/packages/app/src/Element/BadgeList.tsx @@ -3,7 +3,7 @@ import "./BadgeList.css"; import { useState } from "react"; import { FormattedMessage } from "react-intl"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { ProxyImg } from "Element/ProxyImg"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Element/BlockButton.tsx b/packages/app/src/Element/BlockButton.tsx index 10c4859f..3245d76d 100644 --- a/packages/app/src/Element/BlockButton.tsx +++ b/packages/app/src/Element/BlockButton.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useModeration from "Hooks/useModeration"; import messages from "./messages"; diff --git a/packages/app/src/Element/Bookmarks.tsx b/packages/app/src/Element/Bookmarks.tsx index 04680f64..118cf917 100644 --- a/packages/app/src/Element/Bookmarks.tsx +++ b/packages/app/src/Element/Bookmarks.tsx @@ -1,6 +1,6 @@ import { useState, useMemo, ChangeEvent } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey, TaggedRawEvent } from "System"; +import { HexKey, TaggedRawEvent } from "@snort/system"; import Note from "Element/Note"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Element/DM.tsx b/packages/app/src/Element/DM.tsx index de058fee..2a8e9efa 100644 --- a/packages/app/src/Element/DM.tsx +++ b/packages/app/src/Element/DM.tsx @@ -2,7 +2,7 @@ import "./DM.css"; import { useEffect, useState } from "react"; import { useIntl } from "react-intl"; import { useInView } from "react-intersection-observer"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import NoteTime from "Element/NoteTime"; diff --git a/packages/app/src/Element/DmWindow.tsx b/packages/app/src/Element/DmWindow.tsx index 827984b7..b56e95c0 100644 --- a/packages/app/src/Element/DmWindow.tsx +++ b/packages/app/src/Element/DmWindow.tsx @@ -1,6 +1,6 @@ import "./DmWindow.css"; import { useEffect, useMemo, useRef } from "react"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import ProfileImage from "Element/ProfileImage"; import DM from "Element/DM"; diff --git a/packages/app/src/Element/FollowButton.tsx b/packages/app/src/Element/FollowButton.tsx index e284bc83..72e3fb33 100644 --- a/packages/app/src/Element/FollowButton.tsx +++ b/packages/app/src/Element/FollowButton.tsx @@ -1,6 +1,6 @@ import "./FollowButton.css"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import { parseId } from "SnortUtils"; diff --git a/packages/app/src/Element/FollowListBase.tsx b/packages/app/src/Element/FollowListBase.tsx index e98ef131..fc0b09dc 100644 --- a/packages/app/src/Element/FollowListBase.tsx +++ b/packages/app/src/Element/FollowListBase.tsx @@ -1,6 +1,6 @@ import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import ProfilePreview from "Element/ProfilePreview"; diff --git a/packages/app/src/Element/Mention.tsx b/packages/app/src/Element/Mention.tsx index b7a8af60..9fe4723e 100644 --- a/packages/app/src/Element/Mention.tsx +++ b/packages/app/src/Element/Mention.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react"; import { Link } from "react-router-dom"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { profileLink } from "SnortUtils"; diff --git a/packages/app/src/Element/MuteButton.tsx b/packages/app/src/Element/MuteButton.tsx index 7f8d492f..b95d1e21 100644 --- a/packages/app/src/Element/MuteButton.tsx +++ b/packages/app/src/Element/MuteButton.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useModeration from "Hooks/useModeration"; import messages from "./messages"; diff --git a/packages/app/src/Element/MutedList.tsx b/packages/app/src/Element/MutedList.tsx index 6fa9044c..b3ecb946 100644 --- a/packages/app/src/Element/MutedList.tsx +++ b/packages/app/src/Element/MutedList.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import MuteButton from "Element/MuteButton"; import ProfilePreview from "Element/ProfilePreview"; import useModeration from "Hooks/useModeration"; diff --git a/packages/app/src/Element/Nip05.tsx b/packages/app/src/Element/Nip05.tsx index e3e14170..5e1de7ab 100644 --- a/packages/app/src/Element/Nip05.tsx +++ b/packages/app/src/Element/Nip05.tsx @@ -1,5 +1,5 @@ import "./Nip05.css"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import Icon from "Icons/Icon"; import { useUserProfile } from "Hooks/useUserProfile"; diff --git a/packages/app/src/Element/Nip5Service.tsx b/packages/app/src/Element/Nip5Service.tsx index 122c249b..3eb16982 100644 --- a/packages/app/src/Element/Nip5Service.tsx +++ b/packages/app/src/Element/Nip5Service.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState, ChangeEvent } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { UserMetadata } from "System"; +import { UserMetadata, mapEventToProfile } from "@snort/system"; import { unwrap } from "SnortUtils"; import { formatShort } from "Number"; @@ -22,7 +22,7 @@ import useEventPublisher from "Feed/EventPublisher"; import { debounce } from "SnortUtils"; import useLogin from "Hooks/useLogin"; import SnortServiceProvider from "Nip05/SnortServiceProvider"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import messages from "./messages"; diff --git a/packages/app/src/Element/NostrFileHeader.tsx b/packages/app/src/Element/NostrFileHeader.tsx index 512d09df..b4efdc0d 100644 --- a/packages/app/src/Element/NostrFileHeader.tsx +++ b/packages/app/src/Element/NostrFileHeader.tsx @@ -1,7 +1,7 @@ import { FormattedMessage } from "react-intl"; -import { NostrEvent } from "System"; +import { NostrEvent, NostrLink } from "@snort/system"; -import { findTag, NostrLink } from "SnortUtils"; +import { findTag } from "SnortUtils"; import useEventFeed from "Feed/EventFeed"; import PageSpinner from "Element/PageSpinner"; import Reveal from "Element/Reveal"; diff --git a/packages/app/src/Element/NostrLink.tsx b/packages/app/src/Element/NostrLink.tsx index 64efbde8..28ea734a 100644 --- a/packages/app/src/Element/NostrLink.tsx +++ b/packages/app/src/Element/NostrLink.tsx @@ -1,8 +1,7 @@ import { Link } from "react-router-dom"; -import { NostrPrefix } from "System"; +import { NostrPrefix, parseNostrLink } from "@snort/system"; import Mention from "Element/Mention"; -import { parseNostrLink } from "SnortUtils"; import NoteQuote from "Element/NoteQuote"; export default function NostrLink({ link, depth }: { link: string; depth?: number }) { diff --git a/packages/app/src/Element/Note.tsx b/packages/app/src/Element/Note.tsx index 5a582f6a..10115754 100644 --- a/packages/app/src/Element/Note.tsx +++ b/packages/app/src/Element/Note.tsx @@ -3,7 +3,7 @@ import React, { useMemo, useState, useLayoutEffect, ReactNode } from "react"; import { useNavigate, Link } from "react-router-dom"; import { useInView } from "react-intersection-observer"; import { useIntl, FormattedMessage } from "react-intl"; -import { TaggedRawEvent, HexKey, EventKind, NostrPrefix, Lists } from "System"; +import { TaggedRawEvent, HexKey, EventKind, NostrPrefix, Lists, EventExt } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import Icon from "Icons/Icon"; @@ -26,7 +26,6 @@ import Reveal from "Element/Reveal"; import useModeration from "Hooks/useModeration"; import { UserCache } from "Cache/UserCache"; import Poll from "Element/Poll"; -import { EventExt } from "System/EventExt"; import useLogin from "Hooks/useLogin"; import { setBookmarked, setPinned } from "Login"; import { NostrFileElement } from "Element/NostrFileHeader"; diff --git a/packages/app/src/Element/NoteCreator.tsx b/packages/app/src/Element/NoteCreator.tsx index 6a4a2a4a..958cc179 100644 --- a/packages/app/src/Element/NoteCreator.tsx +++ b/packages/app/src/Element/NoteCreator.tsx @@ -1,7 +1,7 @@ import "./NoteCreator.css"; import { FormattedMessage, useIntl } from "react-intl"; import { useDispatch, useSelector } from "react-redux"; -import { encodeTLV, EventKind, NostrPrefix, TaggedRawEvent } from "System"; +import { encodeTLV, EventKind, NostrPrefix, TaggedRawEvent, EventBuilder } from "@snort/system"; import Icon from "Icons/Icon"; import useEventPublisher from "Feed/EventPublisher"; @@ -31,7 +31,6 @@ import { LNURL } from "LNURL"; import messages from "./messages"; import { ClipboardEventHandler, useState } from "react"; import Spinner from "Icons/Spinner"; -import { EventBuilder } from "System"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { LoginStore } from "Login"; import { getCurrentSubscription } from "Subscription"; diff --git a/packages/app/src/Element/NoteFooter.tsx b/packages/app/src/Element/NoteFooter.tsx index 25fef378..800c4d31 100644 --- a/packages/app/src/Element/NoteFooter.tsx +++ b/packages/app/src/Element/NoteFooter.tsx @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from "react-redux"; import { useIntl, FormattedMessage } from "react-intl"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { useLongPress } from "use-long-press"; -import { TaggedRawEvent, HexKey, u256, encodeTLV, NostrPrefix, Lists } from "System"; +import { TaggedRawEvent, HexKey, u256, encodeTLV, NostrPrefix, Lists } from "@snort/system"; import Icon from "Icons/Icon"; import Spinner from "Icons/Spinner"; diff --git a/packages/app/src/Element/NoteQuote.tsx b/packages/app/src/Element/NoteQuote.tsx index 31cca7ba..262b1ca6 100644 --- a/packages/app/src/Element/NoteQuote.tsx +++ b/packages/app/src/Element/NoteQuote.tsx @@ -1,5 +1,5 @@ import useEventFeed from "Feed/EventFeed"; -import { NostrLink } from "SnortUtils"; +import { NostrLink } from "@snort/system"; import Note from "Element/Note"; import PageSpinner from "Element/PageSpinner"; diff --git a/packages/app/src/Element/NoteReaction.tsx b/packages/app/src/Element/NoteReaction.tsx index 1849c904..00301dac 100644 --- a/packages/app/src/Element/NoteReaction.tsx +++ b/packages/app/src/Element/NoteReaction.tsx @@ -1,14 +1,13 @@ import "./NoteReaction.css"; import { Link } from "react-router-dom"; import { useMemo } from "react"; -import { EventKind, NostrEvent, TaggedRawEvent, NostrPrefix } from "System"; +import { EventKind, NostrEvent, TaggedRawEvent, NostrPrefix, EventExt } from "@snort/system"; import Note from "Element/Note"; import ProfileImage from "Element/ProfileImage"; import { eventLink, hexToBech32 } from "SnortUtils"; import NoteTime from "Element/NoteTime"; import useModeration from "Hooks/useModeration"; -import { EventExt } from "System/EventExt"; export interface NoteReactionProps { data: TaggedRawEvent; diff --git a/packages/app/src/Element/Poll.tsx b/packages/app/src/Element/Poll.tsx index bb29730e..4ef7dcf9 100644 --- a/packages/app/src/Element/Poll.tsx +++ b/packages/app/src/Element/Poll.tsx @@ -1,4 +1,4 @@ -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { useState } from "react"; import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; diff --git a/packages/app/src/Element/ProfileImage.tsx b/packages/app/src/Element/ProfileImage.tsx index 96c5e15a..5745b9c7 100644 --- a/packages/app/src/Element/ProfileImage.tsx +++ b/packages/app/src/Element/ProfileImage.tsx @@ -1,13 +1,12 @@ import "./ProfileImage.css"; import React, { useMemo } from "react"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix, MetadataCache } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { hexToBech32, profileLink } from "SnortUtils"; import Avatar from "Element/Avatar"; import Nip05 from "Element/Nip05"; -import { MetadataCache } from "Cache"; import { Link } from "react-router-dom"; export interface ProfileImageProps { diff --git a/packages/app/src/Element/ProfilePreview.tsx b/packages/app/src/Element/ProfilePreview.tsx index 15f02c05..6397e778 100644 --- a/packages/app/src/Element/ProfilePreview.tsx +++ b/packages/app/src/Element/ProfilePreview.tsx @@ -4,7 +4,7 @@ import { ReactNode } from "react"; import ProfileImage from "Element/ProfileImage"; import FollowButton from "Element/FollowButton"; import { useUserProfile } from "Hooks/useUserProfile"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useInView } from "react-intersection-observer"; export interface ProfilePreviewProps { diff --git a/packages/app/src/Element/PubkeyList.tsx b/packages/app/src/Element/PubkeyList.tsx index 6350af3f..5812e6fa 100644 --- a/packages/app/src/Element/PubkeyList.tsx +++ b/packages/app/src/Element/PubkeyList.tsx @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import { dedupe } from "SnortUtils"; import FollowListBase from "./FollowListBase"; diff --git a/packages/app/src/Element/Reactions.tsx b/packages/app/src/Element/Reactions.tsx index 2dcfbe30..8e723277 100644 --- a/packages/app/src/Element/Reactions.tsx +++ b/packages/app/src/Element/Reactions.tsx @@ -2,7 +2,7 @@ import "./Reactions.css"; import { useState, useMemo, useEffect } from "react"; import { useIntl, FormattedMessage } from "react-intl"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { formatShort } from "Number"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Element/Relay.tsx b/packages/app/src/Element/Relay.tsx index e79ed1ab..ab3d3de9 100644 --- a/packages/app/src/Element/Relay.tsx +++ b/packages/app/src/Element/Relay.tsx @@ -2,7 +2,7 @@ import "./Relay.css"; import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { RelaySettings } from "System"; +import { RelaySettings } from "@snort/system"; import useRelayState from "Feed/RelayState"; import { System } from "index"; diff --git a/packages/app/src/Element/RelaysMetadata.tsx b/packages/app/src/Element/RelaysMetadata.tsx index 8973a428..5df1631e 100644 --- a/packages/app/src/Element/RelaysMetadata.tsx +++ b/packages/app/src/Element/RelaysMetadata.tsx @@ -2,7 +2,7 @@ import "./RelaysMetadata.css"; import Nostrich from "nostrich.webp"; import { useState } from "react"; -import { FullRelaySettings } from "System"; +import { FullRelaySettings } from "@snort/system"; import Icon from "Icons/Icon"; const RelayFavicon = ({ url }: { url: string }) => { diff --git a/packages/app/src/Element/SendSats.tsx b/packages/app/src/Element/SendSats.tsx index 765c5929..1c55269d 100644 --- a/packages/app/src/Element/SendSats.tsx +++ b/packages/app/src/Element/SendSats.tsx @@ -2,7 +2,7 @@ import "./SendSats.css"; import React, { useEffect, useMemo, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; -import { HexKey, NostrEvent } from "System"; +import { HexKey, NostrEvent, EventPublisher } from "@snort/system"; import { System } from "index"; import { formatShort } from "Number"; import Icon from "Icons/Icon"; @@ -16,7 +16,6 @@ import { chunks, debounce } from "SnortUtils"; import { useWallet } from "Wallet"; import useLogin from "Hooks/useLogin"; import { generateRandomKey } from "Login"; -import { EventPublisher } from "System/EventPublisher"; import { ZapPoolController } from "ZapPoolController"; import messages from "./messages"; diff --git a/packages/app/src/Element/SubDebug.tsx b/packages/app/src/Element/SubDebug.tsx index 73375741..bf1707fe 100644 --- a/packages/app/src/Element/SubDebug.tsx +++ b/packages/app/src/Element/SubDebug.tsx @@ -5,7 +5,7 @@ import useRelayState from "Feed/RelayState"; import Tabs, { Tab } from "Element/Tabs"; import { unwrap } from "SnortUtils"; import useSystemState from "Hooks/useSystemState"; -import { ReqFilter } from "System"; +import { ReqFilter } from "@snort/system"; import { useCopy } from "useCopy"; import { System } from "index"; diff --git a/packages/app/src/Element/SuggestedProfiles.tsx b/packages/app/src/Element/SuggestedProfiles.tsx index 5cb06808..7d86420c 100644 --- a/packages/app/src/Element/SuggestedProfiles.tsx +++ b/packages/app/src/Element/SuggestedProfiles.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix } from "@snort/system"; import { FormattedMessage } from "react-intl"; import FollowListBase from "Element/FollowListBase"; diff --git a/packages/app/src/Element/Text.tsx b/packages/app/src/Element/Text.tsx index 89ede775..779c35b8 100644 --- a/packages/app/src/Element/Text.tsx +++ b/packages/app/src/Element/Text.tsx @@ -1,10 +1,10 @@ import "./Text.css"; import { useMemo } from "react"; import { Link, useLocation } from "react-router-dom"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix, validateNostrLink } from "@snort/system"; import { MentionRegex, InvoiceRegex, HashtagRegex, CashuRegex } from "Const"; -import { eventLink, hexToBech32, splitByUrl, validateNostrLink } from "SnortUtils"; +import { eventLink, hexToBech32, splitByUrl } from "SnortUtils"; import Invoice from "Element/Invoice"; import Hashtag from "Element/Hashtag"; import Mention from "Element/Mention"; diff --git a/packages/app/src/Element/Textarea.tsx b/packages/app/src/Element/Textarea.tsx index c92c497e..352ade10 100644 --- a/packages/app/src/Element/Textarea.tsx +++ b/packages/app/src/Element/Textarea.tsx @@ -4,12 +4,11 @@ import "./Textarea.css"; import { useIntl } from "react-intl"; import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete"; import TextareaAutosize from "react-textarea-autosize"; -import { NostrPrefix } from "System"; +import { NostrPrefix, MetadataCache } from "@snort/system"; import Avatar from "Element/Avatar"; import Nip05 from "Element/Nip05"; import { hexToBech32 } from "SnortUtils"; -import { MetadataCache } from "Cache"; import { UserCache } from "Cache/UserCache"; import messages from "./messages"; diff --git a/packages/app/src/Element/Thread.tsx b/packages/app/src/Element/Thread.tsx index 2d252382..f30f8966 100644 --- a/packages/app/src/Element/Thread.tsx +++ b/packages/app/src/Element/Thread.tsx @@ -2,10 +2,17 @@ import "./Thread.css"; import { useMemo, useState, ReactNode } from "react"; import { useIntl } from "react-intl"; import { useNavigate, useLocation, Link, useParams } from "react-router-dom"; -import { TaggedRawEvent, u256, EventKind, NostrPrefix } from "System"; -import { EventExt, Thread as ThreadInfo } from "System/EventExt"; +import { + TaggedRawEvent, + u256, + EventKind, + NostrPrefix, + EventExt, + Thread as ThreadInfo, + parseNostrLink, +} from "@snort/system"; -import { eventLink, unwrap, getReactions, parseNostrLink, getAllReactions, findTag } from "SnortUtils"; +import { eventLink, unwrap, getReactions, getAllReactions, findTag } from "SnortUtils"; import BackButton from "Element/BackButton"; import Note from "Element/Note"; import NoteGhost from "Element/NoteGhost"; diff --git a/packages/app/src/Element/Timeline.tsx b/packages/app/src/Element/Timeline.tsx index 1159b1b9..6aa8401e 100644 --- a/packages/app/src/Element/Timeline.tsx +++ b/packages/app/src/Element/Timeline.tsx @@ -2,7 +2,7 @@ import "./Timeline.css"; import { FormattedMessage } from "react-intl"; import { useCallback, useMemo } from "react"; import { useInView } from "react-intersection-observer"; -import { TaggedRawEvent, EventKind, u256 } from "System"; +import { TaggedRawEvent, EventKind, u256 } from "@snort/system"; import Icon from "Icons/Icon"; import { dedupeByPubkey, findTag, tagFilterOfTextRepost } from "SnortUtils"; diff --git a/packages/app/src/Element/TrendingPosts.tsx b/packages/app/src/Element/TrendingPosts.tsx index c46c6e73..863174e6 100644 --- a/packages/app/src/Element/TrendingPosts.tsx +++ b/packages/app/src/Element/TrendingPosts.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { NostrEvent, TaggedRawEvent } from "System"; +import { NostrEvent, TaggedRawEvent } from "@snort/system"; import { FormattedMessage } from "react-intl"; import PageSpinner from "Element/PageSpinner"; diff --git a/packages/app/src/Element/TrendingUsers.tsx b/packages/app/src/Element/TrendingUsers.tsx index 9460b8ab..665acc89 100644 --- a/packages/app/src/Element/TrendingUsers.tsx +++ b/packages/app/src/Element/TrendingUsers.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { FormattedMessage } from "react-intl"; import FollowListBase from "Element/FollowListBase"; diff --git a/packages/app/src/Element/Username.tsx b/packages/app/src/Element/Username.tsx index 47a12ca7..3235cd7d 100644 --- a/packages/app/src/Element/Username.tsx +++ b/packages/app/src/Element/Username.tsx @@ -1,7 +1,7 @@ import { MouseEvent } from "react"; import { useNavigate, Link } from "react-router-dom"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { profileLink } from "SnortUtils"; diff --git a/packages/app/src/Element/WriteDm.tsx b/packages/app/src/Element/WriteDm.tsx index 445437bd..e060c1f7 100644 --- a/packages/app/src/Element/WriteDm.tsx +++ b/packages/app/src/Element/WriteDm.tsx @@ -1,4 +1,4 @@ -import { encodeTLV, NostrPrefix, NostrEvent } from "System"; +import { encodeTLV, NostrPrefix, NostrEvent } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import Icon from "Icons/Icon"; import Spinner from "Icons/Spinner"; diff --git a/packages/app/src/Element/Zap.tsx b/packages/app/src/Element/Zap.tsx index 6a84212b..cb59eee1 100644 --- a/packages/app/src/Element/Zap.tsx +++ b/packages/app/src/Element/Zap.tsx @@ -1,7 +1,7 @@ import "./Zap.css"; import { useMemo } from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import { HexKey, TaggedRawEvent } from "System"; +import { HexKey, TaggedRawEvent } from "@snort/system"; import { decodeInvoice, InvoiceDetails, sha256, unwrap } from "SnortUtils"; import { formatShort } from "Number"; diff --git a/packages/app/src/Element/ZapButton.tsx b/packages/app/src/Element/ZapButton.tsx index ef460d7d..1910fda1 100644 --- a/packages/app/src/Element/ZapButton.tsx +++ b/packages/app/src/Element/ZapButton.tsx @@ -1,6 +1,6 @@ import "./ZapButton.css"; import { useState } from "react"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import SendSats from "Element/SendSats"; diff --git a/packages/app/src/Element/ZapstrEmbed.tsx b/packages/app/src/Element/ZapstrEmbed.tsx index d5ca7f01..844b5b67 100644 --- a/packages/app/src/Element/ZapstrEmbed.tsx +++ b/packages/app/src/Element/ZapstrEmbed.tsx @@ -1,6 +1,6 @@ import "./ZapstrEmbed.css"; import { Link } from "react-router-dom"; -import { encodeTLV, NostrPrefix, NostrEvent } from "System"; +import { encodeTLV, NostrPrefix, NostrEvent } from "@snort/system"; import { ProxyImg } from "Element/ProxyImg"; import ProfileImage from "Element/ProfileImage"; diff --git a/packages/app/src/External/NostrBand.ts b/packages/app/src/External/NostrBand.ts index 8615b61e..8553a460 100644 --- a/packages/app/src/External/NostrBand.ts +++ b/packages/app/src/External/NostrBand.ts @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; export interface TrendingUser { pubkey: string; diff --git a/packages/app/src/Feed/BadgesFeed.ts b/packages/app/src/Feed/BadgesFeed.ts index baf0bacf..8397f8ce 100644 --- a/packages/app/src/Feed/BadgesFeed.ts +++ b/packages/app/src/Feed/BadgesFeed.ts @@ -1,9 +1,7 @@ import { useMemo } from "react"; -import { EventKind, HexKey, Lists } from "System"; +import { EventKind, HexKey, Lists, RequestBuilder, FlatNoteStore, ReplaceableNoteStore } from "@snort/system"; import { unwrap, findTag, chunks } from "SnortUtils"; -import { RequestBuilder } from "System"; -import { FlatNoteStore, ReplaceableNoteStore } from "System/NoteCollection"; import useRequestBuilder from "Hooks/useRequestBuilder"; type BadgeAwards = { diff --git a/packages/app/src/Feed/BookmarkFeed.tsx b/packages/app/src/Feed/BookmarkFeed.tsx index 647cd5b0..2c7da28e 100644 --- a/packages/app/src/Feed/BookmarkFeed.tsx +++ b/packages/app/src/Feed/BookmarkFeed.tsx @@ -1,4 +1,4 @@ -import { HexKey, Lists } from "System"; +import { HexKey, Lists } from "@snort/system"; import useNotelistSubscription from "Hooks/useNotelistSubscription"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/EventFeed.ts b/packages/app/src/Feed/EventFeed.ts index 6ee13f7a..2c295271 100644 --- a/packages/app/src/Feed/EventFeed.ts +++ b/packages/app/src/Feed/EventFeed.ts @@ -1,9 +1,8 @@ import { useMemo } from "react"; -import { NostrPrefix } from "System"; +import { NostrPrefix, RequestBuilder, ReplaceableNoteStore, NostrLink } from "@snort/system"; import useRequestBuilder from "Hooks/useRequestBuilder"; -import { RequestBuilder, ReplaceableNoteStore } from "System"; -import { NostrLink, unwrap } from "SnortUtils"; +import { unwrap } from "SnortUtils"; export default function useEventFeed(link: NostrLink) { const sub = useMemo(() => { diff --git a/packages/app/src/Feed/EventPublisher.ts b/packages/app/src/Feed/EventPublisher.ts index e2eef45c..ff238977 100644 --- a/packages/app/src/Feed/EventPublisher.ts +++ b/packages/app/src/Feed/EventPublisher.ts @@ -1,6 +1,6 @@ import { useMemo } from "react"; import useLogin from "Hooks/useLogin"; -import { EventPublisher } from "System/EventPublisher"; +import { EventPublisher } from "@snort/system"; import { System } from "index"; export default function useEventPublisher() { diff --git a/packages/app/src/Feed/FollowersFeed.ts b/packages/app/src/Feed/FollowersFeed.ts index e8095bce..dc2f79b8 100644 --- a/packages/app/src/Feed/FollowersFeed.ts +++ b/packages/app/src/Feed/FollowersFeed.ts @@ -1,7 +1,6 @@ import { useMemo } from "react"; -import { HexKey, EventKind } from "System"; +import { HexKey, EventKind, PubkeyReplaceableNoteStore, RequestBuilder } from "@snort/system"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useFollowersFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Feed/FollowsFeed.ts b/packages/app/src/Feed/FollowsFeed.ts index b20bef55..5f7b260b 100644 --- a/packages/app/src/Feed/FollowsFeed.ts +++ b/packages/app/src/Feed/FollowsFeed.ts @@ -1,7 +1,6 @@ import { useMemo } from "react"; -import { HexKey, TaggedRawEvent, EventKind } from "System"; +import { HexKey, TaggedRawEvent, EventKind, PubkeyReplaceableNoteStore, RequestBuilder } from "@snort/system"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/LoginFeed.ts b/packages/app/src/Feed/LoginFeed.ts index bf214d7d..bf4a71b6 100644 --- a/packages/app/src/Feed/LoginFeed.ts +++ b/packages/app/src/Feed/LoginFeed.ts @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react"; -import { TaggedRawEvent, Lists, EventKind } from "System"; +import { TaggedRawEvent, Lists, EventKind, FlatNoteStore, RequestBuilder } from "@snort/system"; import debug from "debug"; import { bech32ToHex, getNewest, getNewestEventTagsByKey, unwrap } from "SnortUtils"; @@ -7,7 +7,6 @@ import { makeNotification, sendNotification } from "Notifications"; import useEventPublisher from "Feed/EventPublisher"; import { getMutedKeys } from "Feed/MuteList"; import useModeration from "Hooks/useModeration"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import { DmCache } from "Cache"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/MuteList.ts b/packages/app/src/Feed/MuteList.ts index 3338c496..5e7c75d5 100644 --- a/packages/app/src/Feed/MuteList.ts +++ b/packages/app/src/Feed/MuteList.ts @@ -1,8 +1,14 @@ import { useMemo } from "react"; -import { HexKey, TaggedRawEvent, Lists, EventKind } from "System"; +import { + HexKey, + TaggedRawEvent, + Lists, + EventKind, + ParameterizedReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; import { getNewest } from "SnortUtils"; -import { ParameterizedReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/PinnedFeed.tsx b/packages/app/src/Feed/PinnedFeed.tsx index f55fe40d..bd714903 100644 --- a/packages/app/src/Feed/PinnedFeed.tsx +++ b/packages/app/src/Feed/PinnedFeed.tsx @@ -1,4 +1,4 @@ -import { HexKey, Lists } from "System"; +import { HexKey, Lists } from "@snort/system"; import useNotelistSubscription from "Hooks/useNotelistSubscription"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/RelaysFeed.tsx b/packages/app/src/Feed/RelaysFeed.tsx index 677f5586..e6fe274e 100644 --- a/packages/app/src/Feed/RelaysFeed.tsx +++ b/packages/app/src/Feed/RelaysFeed.tsx @@ -1,8 +1,6 @@ import { useMemo } from "react"; -import { HexKey, FullRelaySettings, EventKind } from "System"; +import { HexKey, FullRelaySettings, EventKind, RequestBuilder, ReplaceableNoteStore } from "@snort/system"; -import { RequestBuilder } from "System"; -import { ReplaceableNoteStore } from "System/NoteCollection"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useRelaysFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Feed/RelaysFeedFollows.tsx b/packages/app/src/Feed/RelaysFeedFollows.tsx index 128fe11f..77367f4d 100644 --- a/packages/app/src/Feed/RelaysFeedFollows.tsx +++ b/packages/app/src/Feed/RelaysFeedFollows.tsx @@ -1,9 +1,16 @@ import { useMemo } from "react"; -import { HexKey, FullRelaySettings, TaggedRawEvent, RelaySettings, EventKind } from "System"; +import { + HexKey, + FullRelaySettings, + TaggedRawEvent, + RelaySettings, + EventKind, + PubkeyReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; import debug from "debug"; import { sanitizeRelayUrl } from "SnortUtils"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import { UserRelays } from "Cache/UserRelayCache"; diff --git a/packages/app/src/Feed/ThreadFeed.ts b/packages/app/src/Feed/ThreadFeed.ts index adbc14f9..1b0af776 100644 --- a/packages/app/src/Feed/ThreadFeed.ts +++ b/packages/app/src/Feed/ThreadFeed.ts @@ -1,8 +1,7 @@ import { useEffect, useMemo, useState } from "react"; -import { u256, EventKind } from "System"; +import { u256, EventKind, NostrLink, FlatNoteStore, RequestBuilder } from "@snort/system"; -import { appendDedupe, NostrLink } from "SnortUtils"; -import { FlatNoteStore, RequestBuilder } from "System"; +import { appendDedupe } from "SnortUtils"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index 8fb8693f..9b8e439b 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -1,8 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import { EventKind, u256 } from "System"; +import { EventKind, u256, FlatNoteStore, RequestBuilder } from "@snort/system"; import { unixNow, unwrap, tagFilterOfTextRepost } from "SnortUtils"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useTimelineWindow from "Hooks/useTimelineWindow"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/ZapsFeed.ts b/packages/app/src/Feed/ZapsFeed.ts index 88694a5e..6fd52ba4 100644 --- a/packages/app/src/Feed/ZapsFeed.ts +++ b/packages/app/src/Feed/ZapsFeed.ts @@ -1,8 +1,7 @@ import { useMemo } from "react"; -import { HexKey, EventKind } from "System"; +import { HexKey, EventKind, FlatNoteStore, RequestBuilder } from "@snort/system"; import { parseZap } from "Element/Zap"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useZapsFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Hooks/useInteractionCache.tsx b/packages/app/src/Hooks/useInteractionCache.tsx index b75e9bf0..46a7521d 100644 --- a/packages/app/src/Hooks/useInteractionCache.tsx +++ b/packages/app/src/Hooks/useInteractionCache.tsx @@ -1,5 +1,5 @@ import { useSyncExternalStore } from "react"; -import { HexKey, u256 } from "System"; +import { HexKey, u256 } from "@snort/system"; import { InteractionCache } from "Cache/EventInteractionCache"; import { EventInteraction } from "Db"; diff --git a/packages/app/src/Hooks/useModeration.tsx b/packages/app/src/Hooks/useModeration.tsx index 2cbd3c7a..3a530c5a 100644 --- a/packages/app/src/Hooks/useModeration.tsx +++ b/packages/app/src/Hooks/useModeration.tsx @@ -1,4 +1,4 @@ -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import useLogin from "Hooks/useLogin"; import { setBlocked, setMuted } from "Login"; diff --git a/packages/app/src/Hooks/useNotelistSubscription.ts b/packages/app/src/Hooks/useNotelistSubscription.ts index 55aa7f95..f9e1eee2 100644 --- a/packages/app/src/Hooks/useNotelistSubscription.ts +++ b/packages/app/src/Hooks/useNotelistSubscription.ts @@ -1,7 +1,13 @@ import { useMemo } from "react"; -import { HexKey, Lists, EventKind } from "System"; +import { + HexKey, + Lists, + EventKind, + FlatNoteStore, + ParameterizedReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; -import { FlatNoteStore, ParameterizedReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Hooks/useRequestBuilder.tsx b/packages/app/src/Hooks/useRequestBuilder.tsx index 6d2fb8a7..d982ed9c 100644 --- a/packages/app/src/Hooks/useRequestBuilder.tsx +++ b/packages/app/src/Hooks/useRequestBuilder.tsx @@ -1,6 +1,5 @@ import { useSyncExternalStore } from "react"; -import { RequestBuilder } from "System"; -import { EmptySnapshot, NoteStore, StoreSnapshot } from "System/NoteCollection"; +import { RequestBuilder, EmptySnapshot, NoteStore, StoreSnapshot } from "@snort/system"; import { unwrap } from "SnortUtils"; import { System } from "index"; diff --git a/packages/app/src/Hooks/useSystemState.tsx b/packages/app/src/Hooks/useSystemState.tsx index 971675be..78932907 100644 --- a/packages/app/src/Hooks/useSystemState.tsx +++ b/packages/app/src/Hooks/useSystemState.tsx @@ -1,5 +1,5 @@ import { useSyncExternalStore } from "react"; -import { SystemSnapshot } from "System"; +import { SystemSnapshot } from "@snort/system"; import { System } from "index"; export default function useSystemState() { diff --git a/packages/app/src/Hooks/useUserProfile.ts b/packages/app/src/Hooks/useUserProfile.ts index 42d68310..3909774a 100644 --- a/packages/app/src/Hooks/useUserProfile.ts +++ b/packages/app/src/Hooks/useUserProfile.ts @@ -1,7 +1,6 @@ import { useEffect, useSyncExternalStore } from "react"; -import { HexKey } from "System"; -import { MetadataCache } from "Cache"; +import { HexKey, MetadataCache } from "@snort/system"; import { UserCache } from "Cache/UserCache"; import { ProfileLoader } from "index"; diff --git a/packages/app/src/LNURL.ts b/packages/app/src/LNURL.ts index 4138bb93..42978610 100644 --- a/packages/app/src/LNURL.ts +++ b/packages/app/src/LNURL.ts @@ -1,4 +1,4 @@ -import { HexKey, NostrEvent } from "System"; +import { HexKey, NostrEvent } from "@snort/system"; import { EmailRegex } from "Const"; import { bech32ToText, unwrap } from "SnortUtils"; diff --git a/packages/app/src/Login/Functions.ts b/packages/app/src/Login/Functions.ts index ac9c37f2..1ba6ffcf 100644 --- a/packages/app/src/Login/Functions.ts +++ b/packages/app/src/Login/Functions.ts @@ -1,4 +1,4 @@ -import { HexKey, RelaySettings } from "System"; +import { HexKey, RelaySettings, EventPublisher } from "@snort/system"; import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; @@ -7,7 +7,6 @@ import { LoginStore, UserPreferences, LoginSession } from "Login"; import { generateBip39Entropy, entropyToPrivateKey } from "nip6"; import { bech32ToHex, dedupeById, randomSample, sanitizeRelayUrl, unixNowMs, unwrap } from "SnortUtils"; import { SubscriptionEvent } from "Subscription"; -import { EventPublisher } from "System/EventPublisher"; import { System } from "index"; export function setRelays(state: LoginSession, relays: Record, createdAt: number) { diff --git a/packages/app/src/Login/LoginSession.ts b/packages/app/src/Login/LoginSession.ts index 95736dd6..3a7fb288 100644 --- a/packages/app/src/Login/LoginSession.ts +++ b/packages/app/src/Login/LoginSession.ts @@ -1,4 +1,4 @@ -import { HexKey, RelaySettings, u256 } from "System"; +import { HexKey, RelaySettings, u256 } from "@snort/system"; import { UserPreferences } from "Login"; import { SubscriptionEvent } from "Subscription"; diff --git a/packages/app/src/Login/MultiAccountStore.ts b/packages/app/src/Login/MultiAccountStore.ts index ddbb4a02..70faea98 100644 --- a/packages/app/src/Login/MultiAccountStore.ts +++ b/packages/app/src/Login/MultiAccountStore.ts @@ -1,7 +1,7 @@ import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; -import { HexKey, RelaySettings } from "System"; +import { HexKey, RelaySettings } from "@snort/system"; import { DefaultRelays } from "Const"; import ExternalStore from "ExternalStore"; diff --git a/packages/app/src/Nip05/SnortServiceProvider.ts b/packages/app/src/Nip05/SnortServiceProvider.ts index fe23ef2a..d6efa314 100644 --- a/packages/app/src/Nip05/SnortServiceProvider.ts +++ b/packages/app/src/Nip05/SnortServiceProvider.ts @@ -1,5 +1,4 @@ -import { EventKind } from "System"; -import { EventPublisher } from "System/EventPublisher"; +import { EventKind, EventPublisher } from "@snort/system"; import { ServiceError, ServiceProvider } from "./ServiceProvider"; export interface ManageHandle { diff --git a/packages/app/src/Notifications.ts b/packages/app/src/Notifications.ts index 09360995..46a4fdef 100644 --- a/packages/app/src/Notifications.ts +++ b/packages/app/src/Notifications.ts @@ -1,7 +1,6 @@ import Nostrich from "nostrich.webp"; -import { TaggedRawEvent, EventKind } from "System"; -import { MetadataCache } from "Cache"; +import { TaggedRawEvent, EventKind, MetadataCache } from "@snort/system"; import { getDisplayName } from "Element/ProfileImage"; import { MentionRegex } from "Const"; import { tagFilterOfTextRepost, unwrap } from "SnortUtils"; diff --git a/packages/app/src/Pages/DonatePage.tsx b/packages/app/src/Pages/DonatePage.tsx index b871f7ac..64517db8 100644 --- a/packages/app/src/Pages/DonatePage.tsx +++ b/packages/app/src/Pages/DonatePage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { ApiHost, KieranPubKey, SnortPubKey } from "Const"; import ProfilePreview from "Element/ProfilePreview"; diff --git a/packages/app/src/Pages/LoginPage.tsx b/packages/app/src/Pages/LoginPage.tsx index faf6e957..be38fea4 100644 --- a/packages/app/src/Pages/LoginPage.tsx +++ b/packages/app/src/Pages/LoginPage.tsx @@ -3,7 +3,7 @@ import "./LoginPage.css"; import { CSSProperties, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useIntl, FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { bech32ToHex, unwrap } from "SnortUtils"; import ZapButton from "Element/ZapButton"; diff --git a/packages/app/src/Pages/MessagesPage.tsx b/packages/app/src/Pages/MessagesPage.tsx index 34f83c7d..3aa0e6e4 100644 --- a/packages/app/src/Pages/MessagesPage.tsx +++ b/packages/app/src/Pages/MessagesPage.tsx @@ -1,7 +1,7 @@ import React, { useMemo, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { HexKey, NostrEvent, NostrPrefix } from "System"; +import { HexKey, NostrEvent, NostrPrefix } from "@snort/system"; import UnreadCount from "Element/UnreadCount"; import ProfileImage, { getDisplayName } from "Element/ProfileImage"; diff --git a/packages/app/src/Pages/NostrLinkHandler.tsx b/packages/app/src/Pages/NostrLinkHandler.tsx index 3a4d966d..ea8f57c5 100644 --- a/packages/app/src/Pages/NostrLinkHandler.tsx +++ b/packages/app/src/Pages/NostrLinkHandler.tsx @@ -1,10 +1,10 @@ -import { NostrPrefix } from "System"; +import { NostrPrefix, parseNostrLink } from "@snort/system"; import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; import Spinner from "Icons/Spinner"; -import { parseNostrLink, profileLink } from "SnortUtils"; +import { profileLink } from "SnortUtils"; import { getNip05PubKey } from "Pages/LoginPage"; export default function NostrLinkHandler() { diff --git a/packages/app/src/Pages/ProfilePage.tsx b/packages/app/src/Pages/ProfilePage.tsx index 25adf365..551b0c8f 100644 --- a/packages/app/src/Pages/ProfilePage.tsx +++ b/packages/app/src/Pages/ProfilePage.tsx @@ -2,9 +2,9 @@ import "./ProfilePage.css"; import { useEffect, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; -import { encodeTLV, EventKind, HexKey, NostrPrefix } from "System"; +import { encodeTLV, EventKind, HexKey, NostrPrefix, parseNostrLink } from "@snort/system"; -import { parseNostrLink, getReactions, unwrap } from "SnortUtils"; +import { getReactions, unwrap } from "SnortUtils"; import { formatShort } from "Number"; import Note from "Element/Note"; import Bookmarks from "Element/Bookmarks"; diff --git a/packages/app/src/Pages/new/ProfileSetup.tsx b/packages/app/src/Pages/new/ProfileSetup.tsx index 20d6864d..26f5f23a 100644 --- a/packages/app/src/Pages/new/ProfileSetup.tsx +++ b/packages/app/src/Pages/new/ProfileSetup.tsx @@ -1,12 +1,13 @@ import { useEffect, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { mapEventToProfile } from "@snort/system"; import Logo from "Element/Logo"; import useEventPublisher from "Feed/EventPublisher"; import useLogin from "Hooks/useLogin"; import { useUserProfile } from "Hooks/useUserProfile"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import AvatarEditor from "Element/AvatarEditor"; import messages from "./messages"; diff --git a/packages/app/src/Pages/settings/Keys.tsx b/packages/app/src/Pages/settings/Keys.tsx index d8871bcc..00958e95 100644 --- a/packages/app/src/Pages/settings/Keys.tsx +++ b/packages/app/src/Pages/settings/Keys.tsx @@ -1,6 +1,6 @@ import "./Keys.css"; import { FormattedMessage } from "react-intl"; -import { encodeTLV, NostrPrefix } from "System"; +import { encodeTLV, NostrPrefix } from "@snort/system"; import Copy from "Element/Copy"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Pages/settings/Profile.tsx b/packages/app/src/Pages/settings/Profile.tsx index 5ce684e4..1918036c 100644 --- a/packages/app/src/Pages/settings/Profile.tsx +++ b/packages/app/src/Pages/settings/Profile.tsx @@ -3,13 +3,14 @@ import Nostrich from "nostrich.webp"; import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { mapEventToProfile } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import { useUserProfile } from "Hooks/useUserProfile"; import { openFile } from "SnortUtils"; import useFileUpload from "Upload"; import AsyncButton from "Element/AsyncButton"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import useLogin from "Hooks/useLogin"; import AvatarEditor from "Element/AvatarEditor"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Pages/settings/Relays.tsx b/packages/app/src/Pages/settings/Relays.tsx index 78b490c7..d5338309 100644 --- a/packages/app/src/Pages/settings/Relays.tsx +++ b/packages/app/src/Pages/settings/Relays.tsx @@ -23,7 +23,6 @@ const RelaySettingsPage = () => { if (publisher) { const ev = await publisher.contactList(login.follows.item, login.relays.item); publisher.broadcast(ev); - publisher.broadcastForBootstrap(ev); try { const onlineRelays = await fetch("https://api.nostr.watch/v1/online").then(r => r.json()); const relayList = await publisher.relayList(login.relays.item); diff --git a/packages/app/src/SnortApi.ts b/packages/app/src/SnortApi.ts index 75dde20a..498346f1 100644 --- a/packages/app/src/SnortApi.ts +++ b/packages/app/src/SnortApi.ts @@ -1,7 +1,6 @@ -import { EventKind } from "System"; +import { EventKind, EventPublisher } from "@snort/system"; import { ApiHost } from "Const"; import { SubscriptionType } from "Subscription"; -import { EventPublisher } from "System/EventPublisher"; export interface RevenueToday { donations: number; diff --git a/packages/app/src/SnortUtils/Utils.test.ts b/packages/app/src/SnortUtils/Utils.test.ts index e40c6979..b91d02ae 100644 --- a/packages/app/src/SnortUtils/Utils.test.ts +++ b/packages/app/src/SnortUtils/Utils.test.ts @@ -1,5 +1,4 @@ -import { NostrPrefix } from "System"; -import { parseNostrLink, tryParseNostrLink } from "."; +import { NostrPrefix } from "@snort/system"; import { splitByUrl, magnetURIDecode, getRelayName } from "."; import { describe, expect } from "@jest/globals"; @@ -93,47 +92,3 @@ describe("getRelayName", () => { expect(output).toEqual("relay.example2.com?broadcast=true"); }); }); - -describe("tryParseNostrLink", () => { - it("is a valid nostr link", () => { - expect(parseNostrLink("nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ - id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", - type: NostrPrefix.PublicKey, - }); - expect(parseNostrLink("web+nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ - id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", - type: NostrPrefix.PublicKey, - }); - expect(parseNostrLink("nostr:note15449edq4qa5wzgqvh8td0q0dp6hwtes4pknsrm7eygeenhlj99xsq94wu9")).toMatchObject({ - id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", - type: NostrPrefix.Note, - }); - expect( - parseNostrLink( - "nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p" - ) - ).toMatchObject({ - id: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", - type: NostrPrefix.Profile, - relays: ["wss://r.x.com", "wss://djbas.sadkb.com"], - }); - expect(parseNostrLink("nostr:nevent1qqs226juks2sw68pyqxtn4khs8ksath9uc2smfcpalvjyvuemlezjngrd87dq")).toMatchObject({ - id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", - type: NostrPrefix.Event, - }); - expect( - parseNostrLink( - "nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu" - ) - ).toMatchObject({ - id: "ipsum", - type: NostrPrefix.Address, - relays: ["wss://relay.nostr.org"], - author: "a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919", - kind: 30023, - }); - }); - test.each(["nostr:npub", "web+nostr:npub", "nostr:nevent1xxx"])("should return false for invalid nostr links", lb => { - expect(tryParseNostrLink(lb)).toBeUndefined(); - }); -}); diff --git a/packages/app/src/SnortUtils/index.ts b/packages/app/src/SnortUtils/index.ts index 5ff04ed4..df89d9f5 100644 --- a/packages/app/src/SnortUtils/index.ts +++ b/packages/app/src/SnortUtils/index.ts @@ -13,12 +13,9 @@ import { EventKind, encodeTLV, NostrPrefix, - decodeTLV, - TLVEntryType, NostrEvent, -} from "System"; -import { MetadataCache } from "Cache"; -import NostrLink from "Element/NostrLink"; + MetadataCache, +} from "@snort/system"; export const sha256 = (str: string | Uint8Array): u256 => { return utils.bytesToHex(hash(str)); @@ -506,113 +503,6 @@ export function getUrlHostname(url?: string) { } } -export interface NostrLink { - type: NostrPrefix; - id: string; - kind?: number; - author?: string; - relays?: Array; - encode(): string; -} - -export function validateNostrLink(link: string): boolean { - try { - const parsedLink = parseNostrLink(link); - if (!parsedLink) { - return false; - } - if (parsedLink.type === NostrPrefix.PublicKey || parsedLink.type === NostrPrefix.Note) { - return parsedLink.id.length === 64; - } - - return true; - } catch { - return false; - } -} - -export function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined { - try { - return parseNostrLink(link, prefixHint); - } catch { - return undefined; - } -} - -export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink { - const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; - - const isPrefix = (prefix: NostrPrefix) => { - return entity.startsWith(prefix); - }; - - if (isPrefix(NostrPrefix.PublicKey)) { - const id = bech32ToHex(entity); - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.PublicKey, - id: id, - encode: () => hexToBech32(NostrPrefix.PublicKey, id), - }; - } else if (isPrefix(NostrPrefix.Note)) { - const id = bech32ToHex(entity); - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Note, - id: id, - encode: () => hexToBech32(NostrPrefix.Note, id), - }; - } else if (isPrefix(NostrPrefix.Profile) || isPrefix(NostrPrefix.Event) || isPrefix(NostrPrefix.Address)) { - const decoded = decodeTLV(entity); - - const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string; - const relays = decoded.filter(a => a.type === TLVEntryType.Relay).map(a => a.value as string); - const author = decoded.find(a => a.type === TLVEntryType.Author)?.value as string; - const kind = decoded.find(a => a.type === TLVEntryType.Kind)?.value as number; - - const encode = () => { - return entity; // return original - }; - if (isPrefix(NostrPrefix.Profile)) { - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Profile, - id, - relays, - kind, - author, - encode, - }; - } else if (isPrefix(NostrPrefix.Event)) { - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Event, - id, - relays, - kind, - author, - encode, - }; - } else if (isPrefix(NostrPrefix.Address)) { - return { - type: NostrPrefix.Address, - id, - relays, - kind, - author, - encode, - }; - } - } else if (prefixHint) { - return { - type: prefixHint, - id: link, - encode: () => hexToBech32(prefixHint, link), - }; - } - throw new Error("Invalid nostr link"); -} - export function sanitizeRelayUrl(url: string) { try { return new URL(url).toString(); diff --git a/packages/app/src/State/NoteCreator.ts b/packages/app/src/State/NoteCreator.ts index f0bf02fd..e6a8dda8 100644 --- a/packages/app/src/State/NoteCreator.ts +++ b/packages/app/src/State/NoteCreator.ts @@ -1,5 +1,5 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { NostrEvent, TaggedRawEvent } from "System"; +import { NostrEvent, TaggedRawEvent } from "@snort/system"; interface NoteCreatorStore { show: boolean; diff --git a/packages/app/src/State/ReBroadcast.ts b/packages/app/src/State/ReBroadcast.ts index 76d0165d..23cc253b 100644 --- a/packages/app/src/State/ReBroadcast.ts +++ b/packages/app/src/State/ReBroadcast.ts @@ -1,5 +1,5 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; interface ReBroadcastStore { show: boolean; diff --git a/packages/app/src/System/Const.ts b/packages/app/src/System/Const.ts deleted file mode 100644 index e3502ce0..00000000 --- a/packages/app/src/System/Const.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Websocket re-connect timeout - */ -export const DefaultConnectTimeout = 2000; diff --git a/packages/app/src/System/Util.test.ts b/packages/app/src/System/Util.test.ts deleted file mode 100644 index 14812019..00000000 --- a/packages/app/src/System/Util.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { distance } from "./Util"; - -describe("distance", () => { - it("should have 0 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "a", - }; - expect(distance(a, b)).toEqual(0); - }); - it("should have 1 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "b", - }; - expect(distance(a, b)).toEqual(1); - }); - it("should have 10 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "a", - kinds: 1, - }; - expect(distance(a, b)).toEqual(10); - }); - it("should have 11 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "b", - kinds: 1, - }; - expect(distance(a, b)).toEqual(11); - }); - it("should have 1 distance, arrays", () => { - const a = { - since: 1, - until: 100, - kinds: [1], - authors: ["kieran", "snort", "c", "d", "e"], - }; - const b = { - since: 1, - until: 100, - kinds: [6969], - authors: ["kieran", "snort", "c", "d", "e"], - }; - expect(distance(a, b)).toEqual(1); - }); - it("should have 1 distance, array change extra", () => { - const a = { - since: 1, - until: 100, - kinds: [1], - authors: ["f", "kieran", "snort", "c", "d"], - }; - const b = { - since: 1, - until: 100, - kinds: [1], - authors: ["kieran", "snort", "c", "d", "e"], - }; - expect(distance(a, b)).toEqual(1); - }); -}); diff --git a/packages/app/src/Tasks/Nip5Task.tsx b/packages/app/src/Tasks/Nip5Task.tsx index fd711a24..c737ca61 100644 --- a/packages/app/src/Tasks/Nip5Task.tsx +++ b/packages/app/src/Tasks/Nip5Task.tsx @@ -1,6 +1,6 @@ import { FormattedMessage } from "react-intl"; import { Link } from "react-router-dom"; -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; import { BaseUITask } from "Tasks"; export class Nip5Task extends BaseUITask { diff --git a/packages/app/src/Tasks/index.ts b/packages/app/src/Tasks/index.ts index 384c80af..c966d1e6 100644 --- a/packages/app/src/Tasks/index.ts +++ b/packages/app/src/Tasks/index.ts @@ -1,4 +1,4 @@ -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; export interface UITask { id: string; diff --git a/packages/app/src/Upload/VoidCat.ts b/packages/app/src/Upload/VoidCat.ts index 269d57cc..8eb8a11a 100644 --- a/packages/app/src/Upload/VoidCat.ts +++ b/packages/app/src/Upload/VoidCat.ts @@ -1,8 +1,7 @@ -import { EventKind } from "System"; +import { EventKind, EventPublisher } from "@snort/system"; import { VoidApi } from "@void-cat/api"; import { FileExtensionRegex, VoidCatHost } from "Const"; -import { EventPublisher } from "System/EventPublisher"; import { UploadResult } from "Upload"; import { magnetURIDecode } from "SnortUtils"; diff --git a/packages/app/src/Upload/index.ts b/packages/app/src/Upload/index.ts index 8cf57586..ce993af4 100644 --- a/packages/app/src/Upload/index.ts +++ b/packages/app/src/Upload/index.ts @@ -1,5 +1,5 @@ import useLogin from "Hooks/useLogin"; -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import NostrBuild from "Upload/NostrBuild"; import VoidCat from "Upload/VoidCat"; diff --git a/packages/app/src/Wallet/NostrWalletConnect.ts b/packages/app/src/Wallet/NostrWalletConnect.ts index 3b4abe53..8a94a523 100644 --- a/packages/app/src/Wallet/NostrWalletConnect.ts +++ b/packages/app/src/Wallet/NostrWalletConnect.ts @@ -1,6 +1,4 @@ -import { Connection, EventKind, NostrEvent } from "System"; -import { EventBuilder } from "System"; -import { EventExt } from "System/EventExt"; +import { Connection, EventKind, NostrEvent, EventBuilder, EventExt } from "@snort/system"; import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "Wallet"; import debug from "debug"; diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 8dfb2a8a..e7f30e0a 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -33,10 +33,9 @@ import { SubscribeRoutes } from "Pages/subscribe"; import ZapPoolPage from "Pages/ZapPool"; import DebugPage from "Pages/Debug"; import { db } from "Db"; -import { preload } from "Cache"; +import { preload, UserCache } from "Cache"; import { LoginStore } from "Login"; -import { ProfileLoaderService } from "System/ProfileCache"; -import { NostrSystem } from "System"; +import { NostrSystem, ProfileLoaderService } from "@snort/system"; import { UserRelays } from "Cache/UserRelayCache"; /** @@ -49,7 +48,7 @@ export const System = new NostrSystem({ /** * Singleton user profile loader */ -export const ProfileLoader = new ProfileLoaderService(System); +export const ProfileLoader = new ProfileLoaderService(System, UserCache); // @ts-expect-error Setting webpack nonce window.__webpack_nonce__ = "ZmlhdGphZiBzYWlkIHNub3J0LnNvY2lhbCBpcyBwcmV0dHkgZ29vZCwgd2UgbWFkZSBpdCE="; diff --git a/packages/system/.npmignore b/packages/system/.npmignore new file mode 100644 index 00000000..9b5e52ea --- /dev/null +++ b/packages/system/.npmignore @@ -0,0 +1,5 @@ +tests/ +src/ +*.tgz +jest.config.js +worker.ts \ No newline at end of file diff --git a/packages/system/dist/Connection.d.ts b/packages/system/dist/Connection.d.ts new file mode 100644 index 00000000..b8205e0c --- /dev/null +++ b/packages/system/dist/Connection.d.ts @@ -0,0 +1,90 @@ +import { ConnectionStats } from "./ConnectionStats"; +import { NostrEvent, ReqCommand, TaggedRawEvent, u256 } from "./Nostr"; +import { RelayInfo } from "./RelayInfo"; +import ExternalStore from "./ExternalStore"; +export type AuthHandler = (challenge: string, relay: string) => Promise; +/** + * Relay settings + */ +export interface RelaySettings { + read: boolean; + write: boolean; +} +/** + * Snapshot of connection stats + */ +export interface ConnectionStateSnapshot { + connected: boolean; + disconnects: number; + avgLatency: number; + events: { + received: number; + send: number; + }; + settings?: RelaySettings; + info?: RelayInfo; + pendingRequests: Array; + activeRequests: Array; + id: string; + ephemeral: boolean; + address: string; +} +export declare class Connection extends ExternalStore { + #private; + Id: string; + Address: string; + Socket: WebSocket | null; + PendingRaw: Array; + PendingRequests: Array<{ + cmd: ReqCommand; + cb: () => void; + }>; + ActiveRequests: Set; + Settings: RelaySettings; + Info?: RelayInfo; + ConnectTimeout: number; + Stats: ConnectionStats; + HasStateChange: boolean; + IsClosed: boolean; + ReconnectTimer: ReturnType | null; + EventsCallback: Map void>; + OnConnected?: () => void; + OnEvent?: (sub: string, e: TaggedRawEvent) => void; + OnEose?: (sub: string) => void; + OnDisconnect?: (id: string) => void; + Auth?: AuthHandler; + AwaitingAuth: Map; + Authed: boolean; + Ephemeral: boolean; + EphemeralTimeout: ReturnType | undefined; + Down: boolean; + constructor(addr: string, options: RelaySettings, auth?: AuthHandler, ephemeral?: boolean); + ResetEphemeralTimeout(): void; + Connect(): Promise; + Close(): void; + OnOpen(): void; + OnClose(e: CloseEvent): void; + OnMessage(e: MessageEvent): void; + OnError(e: Event): void; + /** + * Send event on this connection + */ + SendEvent(e: NostrEvent): void; + /** + * Send event on this connection and wait for OK response + */ + SendAsync(e: NostrEvent, timeout?: number): Promise; + /** + * Using relay document to determine if this relay supports a feature + */ + SupportsNip(n: number): boolean; + /** + * Queue or send command to the relay + * @param cmd The REQ to send to the server + */ + QueueReq(cmd: ReqCommand, cbSent: () => void): void; + CloseReq(id: string): void; + takeSnapshot(): ConnectionStateSnapshot; + _OnAuthAsync(challenge: string): Promise; +} +//# sourceMappingURL=Connection.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Connection.d.ts.map b/packages/system/dist/Connection.d.ts.map new file mode 100644 index 00000000..61f78755 --- /dev/null +++ b/packages/system/dist/Connection.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../src/Connection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Connection.js b/packages/system/dist/Connection.js new file mode 100644 index 00000000..a33148da --- /dev/null +++ b/packages/system/dist/Connection.js @@ -0,0 +1,343 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _Connection_instances, _Connection_SendQueuedRequests, _Connection_ResetQueues, _Connection_SendJson, _Connection_sendPendingRaw, _Connection_sendOnWire, _Connection_maxSubscriptions_get; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Connection = void 0; +const uuid_1 = require("uuid"); +const Const_1 = require("./Const"); +const ConnectionStats_1 = require("./ConnectionStats"); +const Util_1 = require("./Util"); +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +class Connection extends ExternalStore_1.default { + constructor(addr, options, auth, ephemeral = false) { + super(); + _Connection_instances.add(this); + this.Socket = null; + this.PendingRaw = []; + this.PendingRequests = []; + this.ActiveRequests = new Set(); + this.ConnectTimeout = Const_1.DefaultConnectTimeout; + this.Stats = new ConnectionStats_1.ConnectionStats(); + this.HasStateChange = true; + this.Authed = false; + this.Down = true; + this.Id = (0, uuid_1.v4)(); + this.Address = addr; + this.Settings = options; + this.IsClosed = false; + this.ReconnectTimer = null; + this.EventsCallback = new Map(); + this.AwaitingAuth = new Map(); + this.Auth = auth; + this.Ephemeral = ephemeral; + } + ResetEphemeralTimeout() { + if (this.EphemeralTimeout) { + clearTimeout(this.EphemeralTimeout); + } + if (this.Ephemeral) { + this.EphemeralTimeout = setTimeout(() => { + this.Close(); + }, 30000); + } + } + async Connect() { + try { + if (this.Info === undefined) { + const u = new URL(this.Address); + const rsp = await fetch(`${u.protocol === "wss:" ? "https:" : "http:"}//${u.host}`, { + headers: { + accept: "application/nostr+json", + }, + }); + if (rsp.ok) { + const data = await rsp.json(); + for (const [k, v] of Object.entries(data)) { + if (v === "unset" || v === "" || v === "~") { + data[k] = undefined; + } + } + this.Info = data; + } + } + } + catch (e) { + console.warn("Could not load relay information", e); + } + if (this.Socket) { + this.Id = (0, uuid_1.v4)(); + this.Socket.onopen = null; + this.Socket.onmessage = null; + this.Socket.onerror = null; + this.Socket.onclose = null; + } + this.IsClosed = false; + this.Socket = new WebSocket(this.Address); + this.Socket.onopen = () => this.OnOpen(); + this.Socket.onmessage = e => this.OnMessage(e); + this.Socket.onerror = e => this.OnError(e); + this.Socket.onclose = e => this.OnClose(e); + } + Close() { + this.IsClosed = true; + if (this.ReconnectTimer !== null) { + clearTimeout(this.ReconnectTimer); + this.ReconnectTimer = null; + } + this.Socket?.close(); + this.notifyChange(); + } + OnOpen() { + this.ConnectTimeout = Const_1.DefaultConnectTimeout; + console.log(`[${this.Address}] Open!`); + this.Down = false; + if (this.Ephemeral) { + this.ResetEphemeralTimeout(); + } + this.OnConnected?.(); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this); + } + OnClose(e) { + if (!this.IsClosed) { + this.ConnectTimeout = this.ConnectTimeout * 2; + console.log(`[${this.Address}] Closed (${e.reason}), trying again in ${(this.ConnectTimeout / 1000) + .toFixed(0) + .toLocaleString()} sec`); + this.ReconnectTimer = setTimeout(() => { + this.Connect(); + }, this.ConnectTimeout); + this.Stats.Disconnects++; + } + else { + console.log(`[${this.Address}] Closed!`); + this.ReconnectTimer = null; + } + this.OnDisconnect?.(this.Id); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_ResetQueues).call(this); + // reset connection Id on disconnect, for query-tracking + this.Id = (0, uuid_1.v4)(); + this.notifyChange(); + } + OnMessage(e) { + if (e.data.length > 0) { + const msg = JSON.parse(e.data); + const tag = msg[0]; + switch (tag) { + case "AUTH": { + this._OnAuthAsync(msg[1]) + .then(() => __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this)) + .catch(console.error); + this.Stats.EventsReceived++; + this.notifyChange(); + break; + } + case "EVENT": { + this.OnEvent?.(msg[1], { + ...msg[2], + relays: [this.Address], + }); + this.Stats.EventsReceived++; + this.notifyChange(); + break; + } + case "EOSE": { + this.OnEose?.(msg[1]); + break; + } + case "OK": { + // feedback to broadcast call + console.debug(`${this.Address} OK: `, msg); + const id = msg[1]; + if (this.EventsCallback.has(id)) { + const cb = (0, Util_1.unwrap)(this.EventsCallback.get(id)); + this.EventsCallback.delete(id); + cb(msg); + } + break; + } + case "NOTICE": { + console.warn(`[${this.Address}] NOTICE: ${msg[1]}`); + break; + } + default: { + console.warn(`Unknown tag: ${tag}`); + break; + } + } + } + } + OnError(e) { + console.error(e); + this.notifyChange(); + } + /** + * Send event on this connection + */ + SendEvent(e) { + if (!this.Settings.write) { + return; + } + const req = ["EVENT", e]; + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, req); + this.Stats.EventsSent++; + this.notifyChange(); + } + /** + * Send event on this connection and wait for OK response + */ + async SendAsync(e, timeout = 5000) { + return new Promise(resolve => { + if (!this.Settings.write) { + resolve(); + return; + } + const t = setTimeout(() => { + resolve(); + }, timeout); + this.EventsCallback.set(e.id, () => { + clearTimeout(t); + resolve(); + }); + const req = ["EVENT", e]; + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, req); + this.Stats.EventsSent++; + this.notifyChange(); + }); + } + /** + * Using relay document to determine if this relay supports a feature + */ + SupportsNip(n) { + return this.Info?.supported_nips?.some(a => a === n) ?? false; + } + /** + * Queue or send command to the relay + * @param cmd The REQ to send to the server + */ + QueueReq(cmd, cbSent) { + if (this.ActiveRequests.size >= __classPrivateFieldGet(this, _Connection_instances, "a", _Connection_maxSubscriptions_get)) { + this.PendingRequests.push({ + cmd, + cb: cbSent, + }); + console.debug("Queuing:", this.Address, cmd); + } + else { + this.ActiveRequests.add(cmd[1]); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, cmd); + cbSent(); + } + this.notifyChange(); + } + CloseReq(id) { + if (this.ActiveRequests.delete(id)) { + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, ["CLOSE", id]); + this.OnEose?.(id); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendQueuedRequests).call(this); + } + this.notifyChange(); + } + takeSnapshot() { + return { + connected: this.Socket?.readyState === WebSocket.OPEN, + events: { + received: this.Stats.EventsReceived, + send: this.Stats.EventsSent, + }, + avgLatency: this.Stats.Latency.length > 0 + ? this.Stats.Latency.reduce((acc, v) => acc + v, 0) / this.Stats.Latency.length + : 0, + disconnects: this.Stats.Disconnects, + info: this.Info, + id: this.Id, + pendingRequests: [...this.PendingRequests.map(a => a.cmd[1])], + activeRequests: [...this.ActiveRequests], + ephemeral: this.Ephemeral, + address: this.Address, + }; + } + async _OnAuthAsync(challenge) { + const authCleanup = () => { + this.AwaitingAuth.delete(challenge); + }; + if (!this.Auth) { + throw new Error("Auth hook not registered"); + } + this.AwaitingAuth.set(challenge, true); + const authEvent = await this.Auth(challenge, this.Address); + return new Promise(resolve => { + if (!authEvent) { + authCleanup(); + return Promise.reject("no event"); + } + const t = setTimeout(() => { + authCleanup(); + resolve(); + }, 10000); + this.EventsCallback.set(authEvent.id, (msg) => { + clearTimeout(t); + authCleanup(); + if (msg.length > 3 && msg[2] === true) { + this.Authed = true; + } + resolve(); + }); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, ["AUTH", authEvent]); + }); + } +} +exports.Connection = Connection; +_Connection_instances = new WeakSet(), _Connection_SendQueuedRequests = function _Connection_SendQueuedRequests() { + const canSend = __classPrivateFieldGet(this, _Connection_instances, "a", _Connection_maxSubscriptions_get) - this.ActiveRequests.size; + if (canSend > 0) { + for (let x = 0; x < canSend; x++) { + const p = this.PendingRequests.shift(); + if (p) { + this.ActiveRequests.add(p.cmd[1]); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, p.cmd); + p.cb(); + console.debug("Sent pending REQ", this.Address, p.cmd); + } + } + } +}, _Connection_ResetQueues = function _Connection_ResetQueues() { + this.ActiveRequests.clear(); + this.PendingRequests = []; + this.PendingRaw = []; + this.notifyChange(); +}, _Connection_SendJson = function _Connection_SendJson(obj) { + const authPending = !this.Authed && (this.AwaitingAuth.size > 0 || this.Info?.limitation?.auth_required === true); + if (this.Socket?.readyState !== WebSocket.OPEN || authPending) { + this.PendingRaw.push(obj); + if (this.Socket?.readyState === WebSocket.CLOSED && this.Ephemeral && this.IsClosed) { + this.Connect(); + } + return false; + } + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, obj); +}, _Connection_sendPendingRaw = function _Connection_sendPendingRaw() { + while (this.PendingRaw.length > 0) { + const next = this.PendingRaw.shift(); + if (next) { + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, next); + } + } +}, _Connection_sendOnWire = function _Connection_sendOnWire(obj) { + if (this.Socket?.readyState !== WebSocket.OPEN) { + throw new Error(`Socket is not open, state is ${this.Socket?.readyState}`); + } + const json = JSON.stringify(obj); + this.Socket.send(json); + return true; +}, _Connection_maxSubscriptions_get = function _Connection_maxSubscriptions_get() { + return this.Info?.limitation?.max_subscriptions ?? 25; +}; +//# sourceMappingURL=Connection.js.map \ No newline at end of file diff --git a/packages/system/dist/Connection.js.map b/packages/system/dist/Connection.js.map new file mode 100644 index 00000000..67233092 --- /dev/null +++ b/packages/system/dist/Connection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Connection.js","sourceRoot":"","sources":["../src/Connection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.d.ts b/packages/system/dist/ConnectionStats.d.ts new file mode 100644 index 00000000..43be570b --- /dev/null +++ b/packages/system/dist/ConnectionStats.d.ts @@ -0,0 +1,30 @@ +/** + * Stats class for tracking metrics per connection + */ +export declare class ConnectionStats { + /** + * Last n records of how long between REQ->EOSE + */ + Latency: number[]; + /** + * Total number of REQ's sent on this connection + */ + Subs: number; + /** + * Count of REQ which took too long and where abandoned + */ + SubsTimeout: number; + /** + * Total number of EVENT messages received + */ + EventsReceived: number; + /** + * Total number of EVENT messages sent + */ + EventsSent: number; + /** + * Total number of times this connection was lost + */ + Disconnects: number; +} +//# sourceMappingURL=ConnectionStats.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.d.ts.map b/packages/system/dist/ConnectionStats.d.ts.map new file mode 100644 index 00000000..359e6887 --- /dev/null +++ b/packages/system/dist/ConnectionStats.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ConnectionStats.d.ts","sourceRoot":"","sources":["../src/ConnectionStats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAM;IAEvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAK;IAEjB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAK;IAExB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAK;IAE3B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAK;IAEvB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAK;CACzB"} \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.js b/packages/system/dist/ConnectionStats.js new file mode 100644 index 00000000..334cba6d --- /dev/null +++ b/packages/system/dist/ConnectionStats.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ConnectionStats = void 0; +/** + * Stats class for tracking metrics per connection + */ +class ConnectionStats { + constructor() { + /** + * Last n records of how long between REQ->EOSE + */ + this.Latency = []; + /** + * Total number of REQ's sent on this connection + */ + this.Subs = 0; + /** + * Count of REQ which took too long and where abandoned + */ + this.SubsTimeout = 0; + /** + * Total number of EVENT messages received + */ + this.EventsReceived = 0; + /** + * Total number of EVENT messages sent + */ + this.EventsSent = 0; + /** + * Total number of times this connection was lost + */ + this.Disconnects = 0; + } +} +exports.ConnectionStats = ConnectionStats; +//# sourceMappingURL=ConnectionStats.js.map \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.js.map b/packages/system/dist/ConnectionStats.js.map new file mode 100644 index 00000000..90da8778 --- /dev/null +++ b/packages/system/dist/ConnectionStats.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ConnectionStats.js","sourceRoot":"","sources":["../src/ConnectionStats.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,eAAe;IAA5B;QACE;;WAEG;QACH,YAAO,GAAa,EAAE,CAAC;QAEvB;;WAEG;QACH,SAAI,GAAW,CAAC,CAAC;QAEjB;;WAEG;QACH,gBAAW,GAAW,CAAC,CAAC;QAExB;;WAEG;QACH,mBAAc,GAAW,CAAC,CAAC;QAE3B;;WAEG;QACH,eAAU,GAAW,CAAC,CAAC;QAEvB;;WAEG;QACH,gBAAW,GAAW,CAAC,CAAC;IAC1B,CAAC;CAAA;AA9BD,0CA8BC"} \ No newline at end of file diff --git a/packages/system/dist/Const.d.ts b/packages/system/dist/Const.d.ts new file mode 100644 index 00000000..2bf82921 --- /dev/null +++ b/packages/system/dist/Const.d.ts @@ -0,0 +1,13 @@ +/** + * Websocket re-connect timeout + */ +export declare const DefaultConnectTimeout = 2000; +/** + * Hashtag regex + */ +export declare const HashtagRegex: RegExp; +/** + * How long profile cache should be considered valid for + */ +export declare const ProfileCacheExpire: number; +//# sourceMappingURL=Const.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Const.d.ts.map b/packages/system/dist/Const.d.ts.map new file mode 100644 index 00000000..222ed02a --- /dev/null +++ b/packages/system/dist/Const.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Const.d.ts","sourceRoot":"","sources":["../src/Const.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C;;GAEG;AAEH,eAAO,MAAM,YAAY,QAA4C,CAAC;AAGtE;;GAEG;AACF,eAAO,MAAM,kBAAkB,QAAsB,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/Const.js b/packages/system/dist/Const.js new file mode 100644 index 00000000..79573a84 --- /dev/null +++ b/packages/system/dist/Const.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProfileCacheExpire = exports.HashtagRegex = exports.DefaultConnectTimeout = void 0; +/** + * Websocket re-connect timeout + */ +exports.DefaultConnectTimeout = 2000; +/** + * Hashtag regex + */ +// eslint-disable-next-line no-useless-escape +exports.HashtagRegex = /(#[^\s!@#$%^&*()=+.\/,\[{\]};:'"?><]+)/g; +/** + * How long profile cache should be considered valid for + */ +exports.ProfileCacheExpire = 1000 * 60 * 60 * 6; +//# sourceMappingURL=Const.js.map \ No newline at end of file diff --git a/packages/system/dist/Const.js.map b/packages/system/dist/Const.js.map new file mode 100644 index 00000000..113dff7b --- /dev/null +++ b/packages/system/dist/Const.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Const.js","sourceRoot":"","sources":["../src/Const.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;GAEG;AACH,6CAA6C;AAChC,QAAA,YAAY,GAAG,yCAAyC,CAAC;AAGtE;;GAEG;AACW,QAAA,kBAAkB,GAAG,IAAK,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.d.ts b/packages/system/dist/EventBuilder.d.ts new file mode 100644 index 00000000..66b979b2 --- /dev/null +++ b/packages/system/dist/EventBuilder.d.ts @@ -0,0 +1,20 @@ +import { EventKind, HexKey, NostrEvent } from "."; +export declare class EventBuilder { + #private; + kind(k: EventKind): this; + content(c: string): this; + createdAt(n: number): this; + pubKey(k: string): this; + tag(t: Array): EventBuilder; + /** + * Extract mentions + */ + processContent(): this; + build(): NostrEvent; + /** + * Build and sign event + * @param pk Private key to sign event with + */ + buildAndSign(pk: HexKey): Promise; +} +//# sourceMappingURL=EventBuilder.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.d.ts.map b/packages/system/dist/EventBuilder.d.ts.map new file mode 100644 index 00000000..05679aaa --- /dev/null +++ b/packages/system/dist/EventBuilder.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventBuilder.d.ts","sourceRoot":"","sources":["../src/EventBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAe,UAAU,EAAE,MAAM,GAAG,CAAC;AAM/D,qBAAa,YAAY;;IAOvB,IAAI,CAAC,CAAC,EAAE,SAAS;IAKjB,OAAO,CAAC,CAAC,EAAE,MAAM;IAKjB,SAAS,CAAC,CAAC,EAAE,MAAM;IAKnB,MAAM,CAAC,CAAC,EAAE,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY;IAOnC;;OAEG;IACH,cAAc;IAcd,KAAK;IAcL;;;OAGG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM;CAgC9B"} \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.js b/packages/system/dist/EventBuilder.js new file mode 100644 index 00000000..cc346664 --- /dev/null +++ b/packages/system/dist/EventBuilder.js @@ -0,0 +1,113 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _EventBuilder_instances, _EventBuilder_kind, _EventBuilder_content, _EventBuilder_createdAt, _EventBuilder_pubkey, _EventBuilder_tags, _EventBuilder_validate, _EventBuilder_replaceMention, _EventBuilder_addHashtag; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventBuilder = void 0; +const _1 = require("."); +const Const_1 = require("./Const"); +const Util_1 = require("./Util"); +const EventExt_1 = require("./EventExt"); +const NostrLink_1 = require("./NostrLink"); +class EventBuilder { + constructor() { + _EventBuilder_instances.add(this); + _EventBuilder_kind.set(this, void 0); + _EventBuilder_content.set(this, void 0); + _EventBuilder_createdAt.set(this, void 0); + _EventBuilder_pubkey.set(this, void 0); + _EventBuilder_tags.set(this, []); + } + kind(k) { + __classPrivateFieldSet(this, _EventBuilder_kind, k, "f"); + return this; + } + content(c) { + __classPrivateFieldSet(this, _EventBuilder_content, c, "f"); + return this; + } + createdAt(n) { + __classPrivateFieldSet(this, _EventBuilder_createdAt, n, "f"); + return this; + } + pubKey(k) { + __classPrivateFieldSet(this, _EventBuilder_pubkey, k, "f"); + return this; + } + tag(t) { + const duplicate = __classPrivateFieldGet(this, _EventBuilder_tags, "f").some(a => a.length === t.length && a.every((b, i) => b !== a[i])); + if (duplicate) + return this; + __classPrivateFieldGet(this, _EventBuilder_tags, "f").push(t); + return this; + } + /** + * Extract mentions + */ + processContent() { + if (__classPrivateFieldGet(this, _EventBuilder_content, "f")) { + __classPrivateFieldSet(this, _EventBuilder_content, __classPrivateFieldGet(this, _EventBuilder_content, "f").replace(/@n(pub|profile|event|ote|addr|)1[acdefghjklmnpqrstuvwxyz023456789]+/g, m => __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_replaceMention).call(this, m)), "f"); + const hashTags = [...__classPrivateFieldGet(this, _EventBuilder_content, "f").matchAll(Const_1.HashtagRegex)]; + hashTags.map(hashTag => { + __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_addHashtag).call(this, hashTag[0]); + }); + } + return this; + } + build() { + __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_validate).call(this); + const ev = { + id: "", + pubkey: __classPrivateFieldGet(this, _EventBuilder_pubkey, "f") ?? "", + content: __classPrivateFieldGet(this, _EventBuilder_content, "f") ?? "", + kind: __classPrivateFieldGet(this, _EventBuilder_kind, "f"), + created_at: __classPrivateFieldGet(this, _EventBuilder_createdAt, "f") ?? (0, Util_1.unixNow)(), + tags: __classPrivateFieldGet(this, _EventBuilder_tags, "f"), + }; + ev.id = EventExt_1.EventExt.createId(ev); + return ev; + } + /** + * Build and sign event + * @param pk Private key to sign event with + */ + async buildAndSign(pk) { + const ev = this.pubKey((0, Util_1.getPublicKey)(pk)).build(); + await EventExt_1.EventExt.sign(ev, pk); + return ev; + } +} +exports.EventBuilder = EventBuilder; +_EventBuilder_kind = new WeakMap(), _EventBuilder_content = new WeakMap(), _EventBuilder_createdAt = new WeakMap(), _EventBuilder_pubkey = new WeakMap(), _EventBuilder_tags = new WeakMap(), _EventBuilder_instances = new WeakSet(), _EventBuilder_validate = function _EventBuilder_validate() { + if (__classPrivateFieldGet(this, _EventBuilder_kind, "f") === undefined) { + throw new Error("Kind must be set"); + } + if (__classPrivateFieldGet(this, _EventBuilder_pubkey, "f") === undefined) { + throw new Error("Pubkey must be set"); + } +}, _EventBuilder_replaceMention = function _EventBuilder_replaceMention(match) { + const npub = match.slice(1); + const link = (0, NostrLink_1.parseNostrLink)(npub); + if (link) { + if (link.type === _1.NostrPrefix.Profile || link.type === _1.NostrPrefix.PublicKey) { + this.tag(["p", link.id]); + } + return `nostr:${link.encode()}`; + } + else { + return match; + } +}, _EventBuilder_addHashtag = function _EventBuilder_addHashtag(match) { + const tag = match.slice(1); + this.tag(["t", tag.toLowerCase()]); +}; +//# sourceMappingURL=EventBuilder.js.map \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.js.map b/packages/system/dist/EventBuilder.js.map new file mode 100644 index 00000000..81650cdd --- /dev/null +++ b/packages/system/dist/EventBuilder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventBuilder.js","sourceRoot":"","sources":["../src/EventBuilder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/EventExt.d.ts b/packages/system/dist/EventExt.d.ts new file mode 100644 index 00000000..055c952c --- /dev/null +++ b/packages/system/dist/EventExt.d.ts @@ -0,0 +1,42 @@ +import { EventKind, HexKey, NostrEvent, Tag } from "."; +export interface Thread { + root?: Tag; + replyTo?: Tag; + mentions: Array; + pubKeys: Array; +} +export declare abstract class EventExt { + #private; + /** + * Get the pub key of the creator of this event NIP-26 + */ + static getRootPubKey(e: NostrEvent): HexKey; + /** + * Sign this message with a private key + */ + static sign(e: NostrEvent, key: HexKey): void; + /** + * Check the signature of this message + * @returns True if valid signature + */ + static verify(e: NostrEvent): boolean; + static createId(e: NostrEvent): string; + /** + * Create a new event for a specific pubkey + */ + static forPubKey(pk: HexKey, kind: EventKind): NostrEvent; + static extractThread(ev: NostrEvent): Thread | undefined; + /** + * Encrypt the given message content + */ + static encryptData(content: string, pubkey: HexKey, privkey: HexKey): Promise; + /** + * Decrypt the content of the message + */ + static decryptData(cyphertext: string, privkey: HexKey, pubkey: HexKey): Promise; + /** + * Decrypt the content of this message in place + */ + static decryptDm(content: string, privkey: HexKey, pubkey: HexKey): Promise; +} +//# sourceMappingURL=EventExt.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventExt.d.ts.map b/packages/system/dist/EventExt.d.ts.map new file mode 100644 index 00000000..bb09e5ef --- /dev/null +++ b/packages/system/dist/EventExt.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventExt.d.ts","sourceRoot":"","sources":["../src/EventExt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC;AAIvD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,8BAAsB,QAAQ;;IAC5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM;IAS3C;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM;IAUtC;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU;IAM3B,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU;IAW7B;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS;IAY5C,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,UAAU;IAqCnC;;OAEG;WACU,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAgBzE;;OAEG;WACU,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAoB5E;;OAEG;WACU,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CASxE"} \ No newline at end of file diff --git a/packages/system/dist/EventExt.js b/packages/system/dist/EventExt.js new file mode 100644 index 00000000..eb019d83 --- /dev/null +++ b/packages/system/dist/EventExt.js @@ -0,0 +1,175 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _a, _EventExt_getDmSharedKey; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventExt = void 0; +const secp = __importStar(require("@noble/curves/secp256k1")); +const utils = __importStar(require("@noble/curves/abstract/utils")); +const _1 = require("."); +const base64_1 = __importDefault(require("@protobufjs/base64")); +const Util_1 = require("./Util"); +class EventExt { + /** + * Get the pub key of the creator of this event NIP-26 + */ + static getRootPubKey(e) { + const delegation = e.tags.find(a => a[0] === "delegation"); + if (delegation?.[1]) { + // todo: verify sig + return delegation[1]; + } + return e.pubkey; + } + /** + * Sign this message with a private key + */ + static sign(e, key) { + e.id = this.createId(e); + const sig = secp.schnorr.sign(e.id, key); + e.sig = utils.bytesToHex(sig); + if (!(secp.schnorr.verify(e.sig, e.id, e.pubkey))) { + throw new Error("Signing failed"); + } + } + /** + * Check the signature of this message + * @returns True if valid signature + */ + static verify(e) { + const id = this.createId(e); + const result = secp.schnorr.verify(e.sig, id, e.pubkey); + return result; + } + static createId(e) { + const payload = [0, e.pubkey, e.created_at, e.kind, e.tags, e.content]; + const hash = (0, Util_1.sha256)(JSON.stringify(payload)); + if (e.id !== "" && hash !== e.id) { + console.debug(payload); + throw new Error("ID doesnt match!"); + } + return hash; + } + /** + * Create a new event for a specific pubkey + */ + static forPubKey(pk, kind) { + return { + pubkey: pk, + kind: kind, + created_at: (0, Util_1.unixNow)(), + content: "", + tags: [], + id: "", + sig: "", + }; + } + static extractThread(ev) { + const isThread = ev.tags.some(a => (a[0] === "e" && a[3] !== "mention") || a[0] == "a"); + if (!isThread) { + return undefined; + } + const shouldWriteMarkers = ev.kind === _1.EventKind.TextNote; + const ret = { + mentions: [], + pubKeys: [], + }; + const eTags = ev.tags.filter(a => a[0] === "e" || a[0] === "a").map((v, i) => new _1.Tag(v, i)); + const marked = eTags.some(a => a.Marker !== undefined); + if (!marked) { + ret.root = eTags[0]; + ret.root.Marker = shouldWriteMarkers ? "root" : undefined; + if (eTags.length > 1) { + ret.replyTo = eTags[1]; + ret.replyTo.Marker = shouldWriteMarkers ? "reply" : undefined; + } + if (eTags.length > 2) { + ret.mentions = eTags.slice(2); + if (shouldWriteMarkers) { + ret.mentions.forEach(a => (a.Marker = "mention")); + } + } + } + else { + const root = eTags.find(a => a.Marker === "root"); + const reply = eTags.find(a => a.Marker === "reply"); + ret.root = root; + ret.replyTo = reply; + ret.mentions = eTags.filter(a => a.Marker === "mention"); + } + ret.pubKeys = Array.from(new Set(ev.tags.filter(a => a[0] === "p").map(a => a[1]))); + return ret; + } + /** + * Encrypt the given message content + */ + static async encryptData(content, pubkey, privkey) { + const key = await __classPrivateFieldGet(this, _a, "m", _EventExt_getDmSharedKey).call(this, pubkey, privkey); + const iv = window.crypto.getRandomValues(new Uint8Array(16)); + const data = new TextEncoder().encode(content); + const result = await window.crypto.subtle.encrypt({ + name: "AES-CBC", + iv: iv, + }, key, data); + const uData = new Uint8Array(result); + return `${base64_1.default.encode(uData, 0, result.byteLength)}?iv=${base64_1.default.encode(iv, 0, 16)}`; + } + /** + * Decrypt the content of the message + */ + static async decryptData(cyphertext, privkey, pubkey) { + const key = await __classPrivateFieldGet(this, _a, "m", _EventExt_getDmSharedKey).call(this, pubkey, privkey); + const cSplit = cyphertext.split("?iv="); + const data = new Uint8Array(base64_1.default.length(cSplit[0])); + base64_1.default.decode(cSplit[0], data, 0); + const iv = new Uint8Array(base64_1.default.length(cSplit[1])); + base64_1.default.decode(cSplit[1], iv, 0); + const result = await window.crypto.subtle.decrypt({ + name: "AES-CBC", + iv: iv, + }, key, data); + return new TextDecoder().decode(result); + } + /** + * Decrypt the content of this message in place + */ + static async decryptDm(content, privkey, pubkey) { + return await this.decryptData(content, privkey, pubkey); + } +} +exports.EventExt = EventExt; +_a = EventExt, _EventExt_getDmSharedKey = async function _EventExt_getDmSharedKey(pubkey, privkey) { + const sharedPoint = secp.secp256k1.getSharedSecret(privkey, "02" + pubkey); + const sharedX = sharedPoint.slice(1, 33); + return await window.crypto.subtle.importKey("raw", sharedX, { name: "AES-CBC" }, false, ["encrypt", "decrypt"]); +}; +//# sourceMappingURL=EventExt.js.map \ No newline at end of file diff --git a/packages/system/dist/EventExt.js.map b/packages/system/dist/EventExt.js.map new file mode 100644 index 00000000..1af29fd9 --- /dev/null +++ b/packages/system/dist/EventExt.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventExt.js","sourceRoot":"","sources":["../src/EventExt.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAAgD;AAChD,oEAAsD;AACtD,wBAAuD;AACvD,gEAAwC;AACxC,iCAAyC;AASzC,MAAsB,QAAQ;IAC5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,CAAa;QAChC,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QAC3D,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;YACnB,mBAAmB;YACnB,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;SACtB;QACD,OAAO,CAAC,CAAC,MAAM,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,CAAa,EAAE,GAAW;QACpC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAExB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE;YACjD,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;SACnC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,CAAa;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACxD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,CAAa;QAC3B,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAEvE,MAAM,IAAI,GAAG,IAAA,aAAM,EAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC,EAAE,EAAE;YAChC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;SACrC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,EAAU,EAAE,IAAe;QAC1C,OAAO;YACL,MAAM,EAAE,EAAE;YACV,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,IAAA,cAAO,GAAE;YACrB,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,EAAE;YACR,EAAE,EAAE,EAAE;YACN,GAAG,EAAE,EAAE;SACM,CAAC;IAClB,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,EAAc;QACjC,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QACxF,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,kBAAkB,GAAG,EAAE,CAAC,IAAI,KAAK,YAAS,CAAC,QAAQ,CAAC;QAC1D,MAAM,GAAG,GAAG;YACV,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACF,CAAC;QACZ,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,MAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7F,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,EAAE;YACX,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;YAC1D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;gBACpB,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;aAC/D;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;gBACpB,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,kBAAkB,EAAE;oBACtB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;iBACnD;aACF;SACF;aAAM;YACL,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC;YACpD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAChB,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC;YACpB,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;SAC1D;QACD,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpF,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,MAAc,EAAE,OAAe;QACvE,MAAM,GAAG,GAAG,MAAM,uBAAA,IAAI,oCAAgB,MAApB,IAAI,EAAiB,MAAM,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAC/C;YACE,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,EAAE;SACP,EACD,GAAG,EACH,IAAI,CACL,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QACrC,OAAO,GAAG,gBAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,gBAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACxF,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,UAAkB,EAAE,OAAe,EAAE,MAAc;QAC1E,MAAM,GAAG,GAAG,MAAM,uBAAA,IAAI,oCAAgB,MAApB,IAAI,EAAiB,MAAM,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,gBAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,gBAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAElC,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,gBAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,gBAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAC/C;YACE,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,EAAE;SACP,EACD,GAAG,EACH,IAAI,CACL,CAAC;QACF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,OAAe,EAAE,MAAc;QACrE,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;CAOF;AAzJD,4BAyJC;0CALQ,KAAK,mCAAiB,MAAc,EAAE,OAAe;IAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzC,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAClH,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventKind.d.ts b/packages/system/dist/EventKind.d.ts new file mode 100644 index 00000000..620047bd --- /dev/null +++ b/packages/system/dist/EventKind.d.ts @@ -0,0 +1,29 @@ +declare enum EventKind { + Unknown = -1, + SetMetadata = 0, + TextNote = 1, + RecommendServer = 2, + ContactList = 3, + DirectMessage = 4, + Deletion = 5, + Repost = 6, + Reaction = 7, + BadgeAward = 8, + SnortSubscriptions = 1000, + Polls = 6969, + FileHeader = 1063, + Relays = 10002, + Ephemeral = 20000, + Auth = 22242, + PubkeyLists = 30000, + NoteLists = 30001, + TagLists = 30002, + Badge = 30009, + ProfileBadges = 30008, + ZapstrTrack = 31337, + ZapRequest = 9734, + ZapReceipt = 9735, + HttpAuthentication = 27235 +} +export default EventKind; +//# sourceMappingURL=EventKind.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventKind.d.ts.map b/packages/system/dist/EventKind.d.ts.map new file mode 100644 index 00000000..2cf2c3fd --- /dev/null +++ b/packages/system/dist/EventKind.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventKind.d.ts","sourceRoot":"","sources":["../src/EventKind.ts"],"names":[],"mappings":"AAAA,aAAK,SAAS;IACZ,OAAO,KAAK;IACZ,WAAW,IAAI;IACf,QAAQ,IAAI;IACZ,eAAe,IAAI;IACnB,WAAW,IAAI;IACf,aAAa,IAAI;IACjB,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,UAAU,IAAI;IACd,kBAAkB,OAAO;IACzB,KAAK,OAAO;IACZ,UAAU,OAAO;IACjB,MAAM,QAAQ;IACd,SAAS,QAAS;IAClB,IAAI,QAAQ;IACZ,WAAW,QAAQ;IACnB,SAAS,QAAQ;IACjB,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,aAAa,QAAQ;IACrB,WAAW,QAAQ;IACnB,UAAU,OAAO;IACjB,UAAU,OAAO;IACjB,kBAAkB,QAAQ;CAC3B;AAED,eAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventKind.js b/packages/system/dist/EventKind.js new file mode 100644 index 00000000..d4a5c88a --- /dev/null +++ b/packages/system/dist/EventKind.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var EventKind; +(function (EventKind) { + EventKind[EventKind["Unknown"] = -1] = "Unknown"; + EventKind[EventKind["SetMetadata"] = 0] = "SetMetadata"; + EventKind[EventKind["TextNote"] = 1] = "TextNote"; + EventKind[EventKind["RecommendServer"] = 2] = "RecommendServer"; + EventKind[EventKind["ContactList"] = 3] = "ContactList"; + EventKind[EventKind["DirectMessage"] = 4] = "DirectMessage"; + EventKind[EventKind["Deletion"] = 5] = "Deletion"; + EventKind[EventKind["Repost"] = 6] = "Repost"; + EventKind[EventKind["Reaction"] = 7] = "Reaction"; + EventKind[EventKind["BadgeAward"] = 8] = "BadgeAward"; + EventKind[EventKind["SnortSubscriptions"] = 1000] = "SnortSubscriptions"; + EventKind[EventKind["Polls"] = 6969] = "Polls"; + EventKind[EventKind["FileHeader"] = 1063] = "FileHeader"; + EventKind[EventKind["Relays"] = 10002] = "Relays"; + EventKind[EventKind["Ephemeral"] = 20000] = "Ephemeral"; + EventKind[EventKind["Auth"] = 22242] = "Auth"; + EventKind[EventKind["PubkeyLists"] = 30000] = "PubkeyLists"; + EventKind[EventKind["NoteLists"] = 30001] = "NoteLists"; + EventKind[EventKind["TagLists"] = 30002] = "TagLists"; + EventKind[EventKind["Badge"] = 30009] = "Badge"; + EventKind[EventKind["ProfileBadges"] = 30008] = "ProfileBadges"; + EventKind[EventKind["ZapstrTrack"] = 31337] = "ZapstrTrack"; + EventKind[EventKind["ZapRequest"] = 9734] = "ZapRequest"; + EventKind[EventKind["ZapReceipt"] = 9735] = "ZapReceipt"; + EventKind[EventKind["HttpAuthentication"] = 27235] = "HttpAuthentication"; +})(EventKind || (EventKind = {})); +exports.default = EventKind; +//# sourceMappingURL=EventKind.js.map \ No newline at end of file diff --git a/packages/system/dist/EventKind.js.map b/packages/system/dist/EventKind.js.map new file mode 100644 index 00000000..4cdf3259 --- /dev/null +++ b/packages/system/dist/EventKind.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventKind.js","sourceRoot":"","sources":["../src/EventKind.ts"],"names":[],"mappings":";;AAAA,IAAK,SA0BJ;AA1BD,WAAK,SAAS;IACZ,gDAAY,CAAA;IACZ,uDAAe,CAAA;IACf,iDAAY,CAAA;IACZ,+DAAmB,CAAA;IACnB,uDAAe,CAAA;IACf,2DAAiB,CAAA;IACjB,iDAAY,CAAA;IACZ,6CAAU,CAAA;IACV,iDAAY,CAAA;IACZ,qDAAc,CAAA;IACd,wEAAyB,CAAA;IACzB,8CAAY,CAAA;IACZ,wDAAiB,CAAA;IACjB,iDAAc,CAAA;IACd,uDAAkB,CAAA;IAClB,6CAAY,CAAA;IACZ,2DAAmB,CAAA;IACnB,uDAAiB,CAAA;IACjB,qDAAgB,CAAA;IAChB,+CAAa,CAAA;IACb,+DAAqB,CAAA;IACrB,2DAAmB,CAAA;IACnB,wDAAiB,CAAA;IACjB,wDAAiB,CAAA;IACjB,yEAA0B,CAAA;AAC5B,CAAC,EA1BI,SAAS,KAAT,SAAS,QA0Bb;AAED,kBAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.d.ts b/packages/system/dist/EventPublisher.d.ts new file mode 100644 index 00000000..d121228e --- /dev/null +++ b/packages/system/dist/EventPublisher.d.ts @@ -0,0 +1,66 @@ +import { FullRelaySettings, HexKey, Lists, NostrEvent, RelaySettings, SystemInterface, TaggedRawEvent, u256, UserMetadata } from "."; +import { EventBuilder } from "./EventBuilder"; +export type EventBuilderHook = (ev: EventBuilder) => EventBuilder; +declare global { + interface Window { + nostr?: { + getPublicKey: () => Promise; + signEvent: (event: T) => Promise; + getRelays?: () => Promise>; + nip04?: { + encrypt?: (pubkey: HexKey, plaintext: string) => Promise; + decrypt?: (pubkey: HexKey, ciphertext: string) => Promise; + }; + }; + } +} +export declare class EventPublisher { + #private; + constructor(system: SystemInterface, pubKey: string, privKey?: string); + nip4Encrypt(content: string, key: HexKey): Promise; + nip4Decrypt(content: string, otherKey: HexKey): Promise; + nip42Auth(challenge: string, relay: string): Promise; + broadcast(ev: NostrEvent): void; + /** + * Write event to all given relays. + */ + broadcastAll(ev: NostrEvent, relays: string[]): void; + muted(keys: HexKey[], priv: HexKey[]): Promise; + noteList(notes: u256[], list: Lists): Promise; + tags(tags: string[]): Promise; + metadata(obj: UserMetadata): Promise; + /** + * Create a basic text note + */ + note(msg: string, fnExtra?: EventBuilderHook): Promise; + /** + * Create a zap request event for a given target event/profile + * @param amount Millisats amout! + * @param author Author pubkey to tag in the zap + * @param note Note Id to tag in the zap + * @param msg Custom message to be included in the zap + */ + zap(amount: number, author: HexKey, relays: Array, note?: HexKey, msg?: string, fnExtra?: EventBuilderHook): Promise; + /** + * Reply to a note + */ + reply(replyTo: TaggedRawEvent, msg: string, fnExtra?: EventBuilderHook): Promise; + react(evRef: NostrEvent, content?: string): Promise; + relayList(relays: Array | Record): Promise; + contactList(follows: Array, relays: Record): Promise; + /** + * Delete an event (NIP-09) + */ + delete(id: u256): Promise; + /** + * Repost a note (NIP-18) + */ + repost(note: NostrEvent): Promise; + decryptDm(note: NostrEvent): Promise; + sendDm(content: string, to: HexKey): Promise; + generic(fnHook: EventBuilderHook): Promise; +} +//# sourceMappingURL=EventPublisher.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.d.ts.map b/packages/system/dist/EventPublisher.d.ts.map new file mode 100644 index 00000000..10509c14 --- /dev/null +++ b/packages/system/dist/EventPublisher.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventPublisher.d.ts","sourceRoot":"","sources":["../src/EventPublisher.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.js b/packages/system/dist/EventPublisher.js new file mode 100644 index 00000000..e392994a --- /dev/null +++ b/packages/system/dist/EventPublisher.js @@ -0,0 +1,295 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _EventPublisher_instances, _EventPublisher_system, _EventPublisher_pubKey, _EventPublisher_privateKey, _EventPublisher_hasNip07_get, _EventPublisher_eb, _EventPublisher_sign; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventPublisher = void 0; +const secp = __importStar(require("@noble/curves/secp256k1")); +const utils = __importStar(require("@noble/curves/abstract/utils")); +const _1 = require("."); +const Util_1 = require("./Util"); +const EventBuilder_1 = require("./EventBuilder"); +const EventExt_1 = require("./EventExt"); +const WorkQueue_1 = require("./WorkQueue"); +const Nip7Queue = []; +(0, WorkQueue_1.processWorkQueue)(Nip7Queue); +class EventPublisher { + constructor(system, pubKey, privKey) { + _EventPublisher_instances.add(this); + _EventPublisher_system.set(this, void 0); + _EventPublisher_pubKey.set(this, void 0); + _EventPublisher_privateKey.set(this, void 0); + __classPrivateFieldSet(this, _EventPublisher_system, system, "f"); + if (privKey) { + __classPrivateFieldSet(this, _EventPublisher_privateKey, privKey, "f"); + __classPrivateFieldSet(this, _EventPublisher_pubKey, utils.bytesToHex(secp.schnorr.getPublicKey(privKey)), "f"); + } + else { + __classPrivateFieldSet(this, _EventPublisher_pubKey, pubKey, "f"); + } + } + async nip4Encrypt(content, key) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + const nip7PubKey = await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).getPublicKey()); + if (nip7PubKey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + throw new Error("Can't encrypt content, NIP-07 pubkey does not match"); + } + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr?.nip04?.encrypt).call(window.nostr?.nip04, key, content)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await EventExt_1.EventExt.encryptData(content, key, __classPrivateFieldGet(this, _EventPublisher_privateKey, "f")); + } + else { + throw new Error("Can't encrypt content, no private keys available"); + } + } + async nip4Decrypt(content, otherKey) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f") && window.nostr?.nip04?.decrypt) { + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr?.nip04?.decrypt).call(window.nostr?.nip04, otherKey, content)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await EventExt_1.EventExt.decryptDm(content, __classPrivateFieldGet(this, _EventPublisher_privateKey, "f"), otherKey); + } + else { + throw new Error("Can't decrypt content, no private keys available"); + } + } + async nip42Auth(challenge, relay) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Auth); + eb.tag(["relay", relay]); + eb.tag(["challenge", challenge]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + broadcast(ev) { + console.debug(ev); + __classPrivateFieldGet(this, _EventPublisher_system, "f").BroadcastEvent(ev); + } + /** + * Write event to all given relays. + */ + broadcastAll(ev, relays) { + for (const k of relays) { + __classPrivateFieldGet(this, _EventPublisher_system, "f").WriteOnceToRelay(k, ev); + } + } + async muted(keys, priv) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.PubkeyLists); + eb.tag(["d", _1.Lists.Muted]); + keys.forEach(p => { + eb.tag(["p", p]); + }); + if (priv.length > 0) { + const ps = priv.map(p => ["p", p]); + const plaintext = JSON.stringify(ps); + eb.content(await this.nip4Encrypt(plaintext, __classPrivateFieldGet(this, _EventPublisher_pubKey, "f"))); + } + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async noteList(notes, list) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.NoteLists); + eb.tag(["d", list]); + notes.forEach(n => { + eb.tag(["e", n]); + }); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async tags(tags) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TagLists); + eb.tag(["d", _1.Lists.Followed]); + tags.forEach(t => { + eb.tag(["t", t]); + }); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async metadata(obj) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.SetMetadata); + eb.content(JSON.stringify(obj)); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Create a basic text note + */ + async note(msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TextNote); + eb.content(msg); + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Create a zap request event for a given target event/profile + * @param amount Millisats amout! + * @param author Author pubkey to tag in the zap + * @param note Note Id to tag in the zap + * @param msg Custom message to be included in the zap + */ + async zap(amount, author, relays, note, msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.ZapRequest); + eb.content(msg ?? ""); + if (note) { + eb.tag(["e", note]); + } + eb.tag(["p", author]); + eb.tag(["relays", ...relays.map(a => a.trim())]); + eb.tag(["amount", amount.toString()]); + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Reply to a note + */ + async reply(replyTo, msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TextNote); + eb.content(msg); + const thread = EventExt_1.EventExt.extractThread(replyTo); + if (thread) { + if (thread.root || thread.replyTo) { + eb.tag(["e", thread.root?.Event ?? thread.replyTo?.Event ?? "", "", "root"]); + } + eb.tag(["e", replyTo.id, replyTo.relays?.[0] ?? "", "reply"]); + eb.tag(["p", replyTo.pubkey]); + for (const pk of thread.pubKeys) { + if (pk === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + continue; + } + eb.tag(["p", pk]); + } + } + else { + eb.tag(["e", replyTo.id, "", "reply"]); + // dont tag self in replies + if (replyTo.pubkey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + eb.tag(["p", replyTo.pubkey]); + } + } + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async react(evRef, content = "+") { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Reaction); + eb.content(content); + eb.tag(["e", evRef.id]); + eb.tag(["p", evRef.pubkey]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async relayList(relays) { + if (!Array.isArray(relays)) { + relays = Object.entries(relays).map(([k, v]) => ({ + url: k, + settings: v, + })); + } + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Relays); + for (const rx of relays) { + const rTag = ["r", rx.url]; + if (rx.settings.read && !rx.settings.write) { + rTag.push("read"); + } + if (rx.settings.write && !rx.settings.read) { + rTag.push("write"); + } + eb.tag(rTag); + } + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async contactList(follows, relays) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.ContactList); + eb.content(JSON.stringify(relays)); + const temp = new Set(follows.filter(a => a.length === 64).map(a => a.toLowerCase())); + temp.forEach(a => eb.tag(["p", a])); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Delete an event (NIP-09) + */ + async delete(id) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Deletion); + eb.tag(["e", id]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Repost a note (NIP-18) + */ + async repost(note) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Repost); + eb.tag(["e", note.id, ""]); + eb.tag(["p", note.pubkey]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async decryptDm(note) { + if (note.pubkey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f") && !note.tags.some(a => a[1] === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f"))) { + throw new Error("Can't decrypt, DM does not belong to this user"); + } + const otherPubKey = note.pubkey === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f") ? (0, Util_1.unwrap)(note.tags.find(a => a[0] === "p")?.[1]) : note.pubkey; + return await this.nip4Decrypt(note.content, otherPubKey); + } + async sendDm(content, to) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.DirectMessage); + eb.content(await this.nip4Encrypt(content, to)); + eb.tag(["p", to]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async generic(fnHook) { + const eb = new EventBuilder_1.EventBuilder(); + eb.pubKey(__classPrivateFieldGet(this, _EventPublisher_pubKey, "f")); + fnHook(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } +} +exports.EventPublisher = EventPublisher; +_EventPublisher_system = new WeakMap(), _EventPublisher_pubKey = new WeakMap(), _EventPublisher_privateKey = new WeakMap(), _EventPublisher_instances = new WeakSet(), _EventPublisher_hasNip07_get = function _EventPublisher_hasNip07_get() { + return "nostr" in window; +}, _EventPublisher_eb = function _EventPublisher_eb(k) { + const eb = new EventBuilder_1.EventBuilder(); + return eb.pubKey(__classPrivateFieldGet(this, _EventPublisher_pubKey, "f")).kind(k); +}, _EventPublisher_sign = async function _EventPublisher_sign(eb) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + const nip7PubKey = await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).getPublicKey()); + if (nip7PubKey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + throw new Error("Can't sign event, NIP-07 pubkey does not match"); + } + const ev = eb.build(); + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).signEvent(ev)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await eb.buildAndSign(__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")); + } + else { + throw new Error("Can't sign event, no private keys available"); + } +}; +//# sourceMappingURL=EventPublisher.js.map \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.js.map b/packages/system/dist/EventPublisher.js.map new file mode 100644 index 00000000..1f95e3ad --- /dev/null +++ b/packages/system/dist/EventPublisher.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventPublisher.js","sourceRoot":"","sources":["../src/EventPublisher.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.d.ts b/packages/system/dist/ExternalStore.d.ts new file mode 100644 index 00000000..2c483f6d --- /dev/null +++ b/packages/system/dist/ExternalStore.d.ts @@ -0,0 +1,13 @@ +type HookFn = (e?: TSnapshot) => void; +/** + * Simple React hookable store with manual change notifications + */ +export default abstract class ExternalStore { + #private; + hook(fn: HookFn): () => void; + snapshot(): Readonly; + protected notifyChange(sn?: TSnapshot): void; + abstract takeSnapshot(): TSnapshot; +} +export {}; +//# sourceMappingURL=ExternalStore.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.d.ts.map b/packages/system/dist/ExternalStore.d.ts.map new file mode 100644 index 00000000..9c439d8d --- /dev/null +++ b/packages/system/dist/ExternalStore.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ExternalStore.d.ts","sourceRoot":"","sources":["../src/ExternalStore.ts"],"names":[],"mappings":"AAAA,KAAK,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;AAMjD;;GAEG;AACH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa,CAAC,SAAS;;IAKnD,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;IAY1B,QAAQ;IAQR,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,SAAS;IAKrC,QAAQ,CAAC,YAAY,IAAI,SAAS;CACnC"} \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.js b/packages/system/dist/ExternalStore.js new file mode 100644 index 00000000..47daafe4 --- /dev/null +++ b/packages/system/dist/ExternalStore.js @@ -0,0 +1,49 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _ExternalStore_hooks, _ExternalStore_snapshot, _ExternalStore_changed; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Simple React hookable store with manual change notifications + */ +class ExternalStore { + constructor() { + _ExternalStore_hooks.set(this, []); + _ExternalStore_snapshot.set(this, {}); + _ExternalStore_changed.set(this, true); + } + hook(fn) { + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").push({ + fn, + }); + return () => { + const idx = __classPrivateFieldGet(this, _ExternalStore_hooks, "f").findIndex(a => a.fn === fn); + if (idx >= 0) { + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").splice(idx, 1); + } + }; + } + snapshot() { + if (__classPrivateFieldGet(this, _ExternalStore_changed, "f")) { + __classPrivateFieldSet(this, _ExternalStore_snapshot, this.takeSnapshot(), "f"); + __classPrivateFieldSet(this, _ExternalStore_changed, false, "f"); + } + return __classPrivateFieldGet(this, _ExternalStore_snapshot, "f"); + } + notifyChange(sn) { + __classPrivateFieldSet(this, _ExternalStore_changed, true, "f"); + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").forEach(h => h.fn(sn)); + } +} +exports.default = ExternalStore; +_ExternalStore_hooks = new WeakMap(), _ExternalStore_snapshot = new WeakMap(), _ExternalStore_changed = new WeakMap(); +//# sourceMappingURL=ExternalStore.js.map \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.js.map b/packages/system/dist/ExternalStore.js.map new file mode 100644 index 00000000..483f5f23 --- /dev/null +++ b/packages/system/dist/ExternalStore.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ExternalStore.js","sourceRoot":"","sources":["../src/ExternalStore.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAMA;;GAEG;AACH,MAA8B,aAAa;IAA3C;QACE,+BAAuC,EAAE,EAAC;QAC1C,kCAAiC,EAAyB,EAAC;QAC3D,iCAAW,IAAI,EAAC;IA4BlB,CAAC;IA1BC,IAAI,CAAC,EAAqB;QACxB,uBAAA,IAAI,4BAAO,CAAC,IAAI,CAAC;YACf,EAAE;SACH,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,uBAAA,IAAI,4BAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACpD,IAAI,GAAG,IAAI,CAAC,EAAE;gBACZ,uBAAA,IAAI,4BAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;aAC5B;QACH,CAAC,CAAC;IACJ,CAAC;IAED,QAAQ;QACN,IAAI,uBAAA,IAAI,8BAAS,EAAE;YACjB,uBAAA,IAAI,2BAAa,IAAI,CAAC,YAAY,EAAE,MAAA,CAAC;YACrC,uBAAA,IAAI,0BAAY,KAAK,MAAA,CAAC;SACvB;QACD,OAAO,uBAAA,IAAI,+BAAU,CAAC;IACxB,CAAC;IAES,YAAY,CAAC,EAAc;QACnC,uBAAA,IAAI,0BAAY,IAAI,MAAA,CAAC;QACrB,uBAAA,IAAI,4BAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;CAGF;AA/BD,gCA+BC"} \ No newline at end of file diff --git a/packages/system/dist/GossipModel.d.ts b/packages/system/dist/GossipModel.d.ts new file mode 100644 index 00000000..a4e1c8b8 --- /dev/null +++ b/packages/system/dist/GossipModel.d.ts @@ -0,0 +1,20 @@ +import { FullRelaySettings, ReqFilter } from "."; +export interface RelayTaggedFilter { + relay: string; + filter: ReqFilter; +} +export interface RelayTaggedFilters { + relay: string; + filters: Array; +} +export interface RelayCache { + get(pubkey?: string): Array | undefined; +} +export declare function splitAllByWriteRelays(cache: RelayCache, filters: Array): RelayTaggedFilters[]; +/** + * Split filters by authors + * @param filter + * @returns + */ +export declare function splitByWriteRelays(cache: RelayCache, filter: ReqFilter): Array; +//# sourceMappingURL=GossipModel.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/GossipModel.d.ts.map b/packages/system/dist/GossipModel.d.ts.map new file mode 100644 index 00000000..3328b5e2 --- /dev/null +++ b/packages/system/dist/GossipModel.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"GossipModel.d.ts","sourceRoot":"","sources":["../src/GossipModel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAMjD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,wBAqBjF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAoEjG"} \ No newline at end of file diff --git a/packages/system/dist/GossipModel.js b/packages/system/dist/GossipModel.js new file mode 100644 index 00000000..1668805e --- /dev/null +++ b/packages/system/dist/GossipModel.js @@ -0,0 +1,102 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.splitByWriteRelays = exports.splitAllByWriteRelays = void 0; +const Util_1 = require("./Util"); +const debug_1 = __importDefault(require("debug")); +const PickNRelays = 2; +function splitAllByWriteRelays(cache, filters) { + const allSplit = filters + .map(a => splitByWriteRelays(cache, a)) + .reduce((acc, v) => { + for (const vn of v) { + const existing = acc.get(vn.relay); + if (existing) { + existing.push(vn.filter); + } + else { + acc.set(vn.relay, [vn.filter]); + } + } + return acc; + }, new Map()); + return [...allSplit.entries()].map(([k, v]) => { + return { + relay: k, + filters: v, + }; + }); +} +exports.splitAllByWriteRelays = splitAllByWriteRelays; +/** + * Split filters by authors + * @param filter + * @returns + */ +function splitByWriteRelays(cache, filter) { + if ((filter.authors?.length ?? 0) === 0) + return [ + { + relay: "", + filter, + }, + ]; + const allRelays = (0, Util_1.unwrap)(filter.authors).map(a => { + return { + key: a, + relays: cache.get(a)?.filter(a => a.settings.write), + }; + }); + const missing = allRelays.filter(a => a.relays === undefined); + const hasRelays = allRelays.filter(a => a.relays !== undefined); + const relayUserMap = hasRelays.reduce((acc, v) => { + for (const r of (0, Util_1.unwrap)(v.relays)) { + if (!acc.has(r.url)) { + acc.set(r.url, new Set([v.key])); + } + else { + (0, Util_1.unwrap)(acc.get(r.url)).add(v.key); + } + } + return acc; + }, new Map()); + // selection algo will just pick relays with the most users + const topRelays = [...relayUserMap.entries()].sort(([, v], [, v1]) => v1.size - v.size); + // - count keys per relay + // - pick n top relays + // - map keys per relay (for subscription filter) + const userPickedRelays = (0, Util_1.unwrap)(filter.authors).map(k => { + // pick top 3 relays for this key + const relaysForKey = topRelays + .filter(([, v]) => v.has(k)) + .slice(0, PickNRelays) + .map(([k]) => k); + return { k, relaysForKey }; + }); + const pickedRelays = new Set(userPickedRelays.map(a => a.relaysForKey).flat()); + const picked = [...pickedRelays].map(a => { + const keysOnPickedRelay = new Set(userPickedRelays.filter(b => b.relaysForKey.includes(a)).map(b => b.k)); + return { + relay: a, + filter: { + ...filter, + authors: [...keysOnPickedRelay], + }, + }; + }); + if (missing.length > 0) { + picked.push({ + relay: "", + filter: { + ...filter, + authors: missing.map(a => a.key), + }, + }); + } + (0, debug_1.default)("GOSSIP")("Picked %o", picked); + return picked; +} +exports.splitByWriteRelays = splitByWriteRelays; +//# sourceMappingURL=GossipModel.js.map \ No newline at end of file diff --git a/packages/system/dist/GossipModel.js.map b/packages/system/dist/GossipModel.js.map new file mode 100644 index 00000000..0bddddb1 --- /dev/null +++ b/packages/system/dist/GossipModel.js.map @@ -0,0 +1 @@ +{"version":3,"file":"GossipModel.js","sourceRoot":"","sources":["../src/GossipModel.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Links.d.ts b/packages/system/dist/Links.d.ts new file mode 100644 index 00000000..bd3ed4c0 --- /dev/null +++ b/packages/system/dist/Links.d.ts @@ -0,0 +1,24 @@ +import { HexKey } from "./Nostr"; +export declare enum NostrPrefix { + PublicKey = "npub", + PrivateKey = "nsec", + Note = "note", + Profile = "nprofile", + Event = "nevent", + Relay = "nrelay", + Address = "naddr" +} +export declare enum TLVEntryType { + Special = 0, + Relay = 1, + Author = 2, + Kind = 3 +} +export interface TLVEntry { + type: TLVEntryType; + length: number; + value: string | HexKey | number; +} +export declare function encodeTLV(prefix: NostrPrefix, id: string, relays?: string[], kind?: number, author?: string): string; +export declare function decodeTLV(str: string): TLVEntry[]; +//# sourceMappingURL=Links.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Links.d.ts.map b/packages/system/dist/Links.d.ts.map new file mode 100644 index 00000000..a7158f31 --- /dev/null +++ b/packages/system/dist/Links.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Links.d.ts","sourceRoot":"","sources":["../src/Links.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,oBAAY,WAAW;IACrB,SAAS,SAAS;IAClB,UAAU,SAAS;IACnB,IAAI,SAAS;IAGb,OAAO,aAAa;IACpB,KAAK,WAAW;IAChB,KAAK,WAAW;IAChB,OAAO,UAAU;CAClB;AAED,oBAAY,YAAY;IACtB,OAAO,IAAI;IACX,KAAK,IAAI;IACT,MAAM,IAAI;IACV,IAAI,IAAI;CACT;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,UAiB3G;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,cAkBpC"} \ No newline at end of file diff --git a/packages/system/dist/Links.js b/packages/system/dist/Links.js new file mode 100644 index 00000000..727ae9de --- /dev/null +++ b/packages/system/dist/Links.js @@ -0,0 +1,102 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decodeTLV = exports.encodeTLV = exports.TLVEntryType = exports.NostrPrefix = void 0; +const utils = __importStar(require("@noble/curves/abstract/utils")); +const bech32_1 = require("bech32"); +var NostrPrefix; +(function (NostrPrefix) { + NostrPrefix["PublicKey"] = "npub"; + NostrPrefix["PrivateKey"] = "nsec"; + NostrPrefix["Note"] = "note"; + // TLV prefixes + NostrPrefix["Profile"] = "nprofile"; + NostrPrefix["Event"] = "nevent"; + NostrPrefix["Relay"] = "nrelay"; + NostrPrefix["Address"] = "naddr"; +})(NostrPrefix = exports.NostrPrefix || (exports.NostrPrefix = {})); +var TLVEntryType; +(function (TLVEntryType) { + TLVEntryType[TLVEntryType["Special"] = 0] = "Special"; + TLVEntryType[TLVEntryType["Relay"] = 1] = "Relay"; + TLVEntryType[TLVEntryType["Author"] = 2] = "Author"; + TLVEntryType[TLVEntryType["Kind"] = 3] = "Kind"; +})(TLVEntryType = exports.TLVEntryType || (exports.TLVEntryType = {})); +function encodeTLV(prefix, id, relays, kind, author) { + const enc = new TextEncoder(); + const buf = prefix === NostrPrefix.Address ? enc.encode(id) : utils.hexToBytes(id); + const tl0 = [0, buf.length, ...buf]; + const tl1 = relays + ?.map(a => { + const data = enc.encode(a); + return [1, data.length, ...data]; + }) + .flat() ?? []; + const tl2 = author ? [2, 32, ...utils.hexToBytes(author)] : []; + const tl3 = kind ? [3, 4, ...new Uint8Array(new Uint32Array([kind]).buffer).reverse()] : []; + return bech32_1.bech32.encode(prefix, bech32_1.bech32.toWords([...tl0, ...tl1, ...tl2, ...tl3]), 1000); +} +exports.encodeTLV = encodeTLV; +function decodeTLV(str) { + const decoded = bech32_1.bech32.decode(str, 1000); + const data = bech32_1.bech32.fromWords(decoded.words); + const entries = []; + let x = 0; + while (x < data.length) { + const t = data[x]; + const l = data[x + 1]; + const v = data.slice(x + 2, x + 2 + l); + entries.push({ + type: t, + length: l, + value: decodeTLVEntry(t, decoded.prefix, new Uint8Array(v)), + }); + x += 2 + l; + } + return entries; +} +exports.decodeTLV = decodeTLV; +function decodeTLVEntry(type, prefix, data) { + switch (type) { + case TLVEntryType.Special: { + if (prefix === NostrPrefix.Address) { + return new TextDecoder("ASCII").decode(data); + } + else { + return utils.bytesToHex(data); + } + } + case TLVEntryType.Author: { + return utils.bytesToHex(data); + } + case TLVEntryType.Kind: { + return new Uint32Array(new Uint8Array(data.reverse()).buffer)[0]; + } + case TLVEntryType.Relay: { + return new TextDecoder("ASCII").decode(data); + } + } +} +//# sourceMappingURL=Links.js.map \ No newline at end of file diff --git a/packages/system/dist/Links.js.map b/packages/system/dist/Links.js.map new file mode 100644 index 00000000..277242a7 --- /dev/null +++ b/packages/system/dist/Links.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Links.js","sourceRoot":"","sources":["../src/Links.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Nips.d.ts b/packages/system/dist/Nips.d.ts new file mode 100644 index 00000000..e3486652 --- /dev/null +++ b/packages/system/dist/Nips.d.ts @@ -0,0 +1,4 @@ +export declare enum Nips { + Search = 50 +} +//# sourceMappingURL=Nips.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Nips.d.ts.map b/packages/system/dist/Nips.d.ts.map new file mode 100644 index 00000000..42dcd779 --- /dev/null +++ b/packages/system/dist/Nips.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Nips.d.ts","sourceRoot":"","sources":["../src/Nips.ts"],"names":[],"mappings":"AAAA,oBAAY,IAAI;IACd,MAAM,KAAK;CACZ"} \ No newline at end of file diff --git a/packages/system/dist/Nips.js b/packages/system/dist/Nips.js new file mode 100644 index 00000000..80b98f7c --- /dev/null +++ b/packages/system/dist/Nips.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Nips = void 0; +var Nips; +(function (Nips) { + Nips[Nips["Search"] = 50] = "Search"; +})(Nips = exports.Nips || (exports.Nips = {})); +//# sourceMappingURL=Nips.js.map \ No newline at end of file diff --git a/packages/system/dist/Nips.js.map b/packages/system/dist/Nips.js.map new file mode 100644 index 00000000..b5276f39 --- /dev/null +++ b/packages/system/dist/Nips.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Nips.js","sourceRoot":"","sources":["../src/Nips.ts"],"names":[],"mappings":";;;AAAA,IAAY,IAEX;AAFD,WAAY,IAAI;IACd,oCAAW,CAAA;AACb,CAAC,EAFW,IAAI,GAAJ,YAAI,KAAJ,YAAI,QAEf"} \ No newline at end of file diff --git a/packages/system/dist/Nostr.d.ts b/packages/system/dist/Nostr.d.ts new file mode 100644 index 00000000..040af7b8 --- /dev/null +++ b/packages/system/dist/Nostr.d.ts @@ -0,0 +1,75 @@ +import { RelaySettings } from "./Connection"; +export interface NostrEvent { + id: u256; + pubkey: HexKey; + created_at: number; + kind: number; + tags: Array>; + content: string; + sig: string; +} +export interface TaggedRawEvent extends NostrEvent { + /** + * A list of relays this event was seen on + */ + relays: string[]; +} +/** + * Basic raw key as hex + */ +export type HexKey = string; +/** + * Optional HexKey + */ +export type MaybeHexKey = HexKey | undefined; +/** + * A 256bit hex id + */ +export type u256 = string; +export type ReqCommand = [cmd: "REQ", id: string, ...filters: Array]; +/** + * Raw REQ filter object + */ +export interface ReqFilter { + ids?: u256[]; + authors?: u256[]; + kinds?: number[]; + "#e"?: u256[]; + "#p"?: u256[]; + "#t"?: string[]; + "#d"?: string[]; + "#r"?: string[]; + search?: string; + since?: number; + until?: number; + limit?: number; +} +/** + * Medatadata event content + */ +export type UserMetadata = { + name?: string; + display_name?: string; + about?: string; + picture?: string; + website?: string; + banner?: string; + nip05?: string; + lud06?: string; + lud16?: string; +}; +/** + * NIP-51 list types + */ +export declare enum Lists { + Muted = "mute", + Pinned = "pin", + Bookmarked = "bookmark", + Followed = "follow", + Badges = "profile_badges" +} +export interface FullRelaySettings { + url: string; + settings: RelaySettings; +} +//# sourceMappingURL=Nostr.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Nostr.d.ts.map b/packages/system/dist/Nostr.d.ts.map new file mode 100644 index 00000000..6e003def --- /dev/null +++ b/packages/system/dist/Nostr.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Nostr.d.ts","sourceRoot":"","sources":["../src/Nostr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;IACb,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,oBAAY,KAAK;IACf,KAAK,SAAS;IACd,MAAM,QAAQ;IACd,UAAU,aAAa;IACvB,QAAQ,WAAW;IACnB,MAAM,mBAAmB;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,aAAa,CAAC;CACzB"} \ No newline at end of file diff --git a/packages/system/dist/Nostr.js b/packages/system/dist/Nostr.js new file mode 100644 index 00000000..5c2cad16 --- /dev/null +++ b/packages/system/dist/Nostr.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Lists = void 0; +/** + * NIP-51 list types + */ +var Lists; +(function (Lists) { + Lists["Muted"] = "mute"; + Lists["Pinned"] = "pin"; + Lists["Bookmarked"] = "bookmark"; + Lists["Followed"] = "follow"; + Lists["Badges"] = "profile_badges"; +})(Lists = exports.Lists || (exports.Lists = {})); +//# sourceMappingURL=Nostr.js.map \ No newline at end of file diff --git a/packages/system/dist/Nostr.js.map b/packages/system/dist/Nostr.js.map new file mode 100644 index 00000000..1100ff69 --- /dev/null +++ b/packages/system/dist/Nostr.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Nostr.js","sourceRoot":"","sources":["../src/Nostr.ts"],"names":[],"mappings":";;;AAqEA;;GAEG;AACH,IAAY,KAMX;AAND,WAAY,KAAK;IACf,uBAAc,CAAA;IACd,uBAAc,CAAA;IACd,gCAAuB,CAAA;IACvB,4BAAmB,CAAA;IACnB,kCAAyB,CAAA;AAC3B,CAAC,EANW,KAAK,GAAL,aAAK,KAAL,aAAK,QAMhB"} \ No newline at end of file diff --git a/packages/system/dist/NostrLink.d.ts b/packages/system/dist/NostrLink.d.ts new file mode 100644 index 00000000..8d22c067 --- /dev/null +++ b/packages/system/dist/NostrLink.d.ts @@ -0,0 +1,13 @@ +import { NostrPrefix } from "."; +export interface NostrLink { + type: NostrPrefix; + id: string; + kind?: number; + author?: string; + relays?: Array; + encode(): string; +} +export declare function validateNostrLink(link: string): boolean; +export declare function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined; +export declare function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink; +//# sourceMappingURL=NostrLink.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NostrLink.d.ts.map b/packages/system/dist/NostrLink.d.ts.map new file mode 100644 index 00000000..ab1d2006 --- /dev/null +++ b/packages/system/dist/NostrLink.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrLink.d.ts","sourceRoot":"","sources":["../src/NostrLink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA2B,MAAM,GAAG,CAAC;AAEzD,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,IAAI,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAcvD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAM/F;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,CAwEhF"} \ No newline at end of file diff --git a/packages/system/dist/NostrLink.js b/packages/system/dist/NostrLink.js new file mode 100644 index 00000000..18cecd68 --- /dev/null +++ b/packages/system/dist/NostrLink.js @@ -0,0 +1,110 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseNostrLink = exports.tryParseNostrLink = exports.validateNostrLink = void 0; +const Util_1 = require("./Util"); +const _1 = require("."); +function validateNostrLink(link) { + try { + const parsedLink = parseNostrLink(link); + if (!parsedLink) { + return false; + } + if (parsedLink.type === _1.NostrPrefix.PublicKey || parsedLink.type === _1.NostrPrefix.Note) { + return parsedLink.id.length === 64; + } + return true; + } + catch { + return false; + } +} +exports.validateNostrLink = validateNostrLink; +function tryParseNostrLink(link, prefixHint) { + try { + return parseNostrLink(link, prefixHint); + } + catch { + return undefined; + } +} +exports.tryParseNostrLink = tryParseNostrLink; +function parseNostrLink(link, prefixHint) { + const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; + const isPrefix = (prefix) => { + return entity.startsWith(prefix); + }; + if (isPrefix(_1.NostrPrefix.PublicKey)) { + const id = (0, Util_1.bech32ToHex)(entity); + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.PublicKey, + id: id, + encode: () => (0, Util_1.hexToBech32)(_1.NostrPrefix.PublicKey, id), + }; + } + else if (isPrefix(_1.NostrPrefix.Note)) { + const id = (0, Util_1.bech32ToHex)(entity); + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Note, + id: id, + encode: () => (0, Util_1.hexToBech32)(_1.NostrPrefix.Note, id), + }; + } + else if (isPrefix(_1.NostrPrefix.Profile) || isPrefix(_1.NostrPrefix.Event) || isPrefix(_1.NostrPrefix.Address)) { + const decoded = (0, _1.decodeTLV)(entity); + const id = decoded.find(a => a.type === _1.TLVEntryType.Special)?.value; + const relays = decoded.filter(a => a.type === _1.TLVEntryType.Relay).map(a => a.value); + const author = decoded.find(a => a.type === _1.TLVEntryType.Author)?.value; + const kind = decoded.find(a => a.type === _1.TLVEntryType.Kind)?.value; + const encode = () => { + return entity; // return original + }; + if (isPrefix(_1.NostrPrefix.Profile)) { + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Profile, + id, + relays, + kind, + author, + encode, + }; + } + else if (isPrefix(_1.NostrPrefix.Event)) { + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Event, + id, + relays, + kind, + author, + encode, + }; + } + else if (isPrefix(_1.NostrPrefix.Address)) { + return { + type: _1.NostrPrefix.Address, + id, + relays, + kind, + author, + encode, + }; + } + } + else if (prefixHint) { + return { + type: prefixHint, + id: link, + encode: () => (0, Util_1.hexToBech32)(prefixHint, link), + }; + } + throw new Error("Invalid nostr link"); +} +exports.parseNostrLink = parseNostrLink; +//# sourceMappingURL=NostrLink.js.map \ No newline at end of file diff --git a/packages/system/dist/NostrLink.js.map b/packages/system/dist/NostrLink.js.map new file mode 100644 index 00000000..8ad349a3 --- /dev/null +++ b/packages/system/dist/NostrLink.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrLink.js","sourceRoot":"","sources":["../src/NostrLink.ts"],"names":[],"mappings":";;;AAAA,iCAAkD;AAClD,wBAAyD;AAWvD,SAAgB,iBAAiB,CAAC,IAAY;IAC5C,IAAI;QACF,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,UAAU,EAAE;YACf,OAAO,KAAK,CAAC;SACd;QACD,IAAI,UAAU,CAAC,IAAI,KAAK,cAAW,CAAC,SAAS,IAAI,UAAU,CAAC,IAAI,KAAK,cAAW,CAAC,IAAI,EAAE;YACrF,OAAO,UAAU,CAAC,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC;SACpC;QAED,OAAO,IAAI,CAAC;KACb;IAAC,MAAM;QACN,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAdD,8CAcC;AAED,SAAgB,iBAAiB,CAAC,IAAY,EAAE,UAAwB;IACtE,IAAI;QACF,OAAO,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;KACzC;IAAC,MAAM;QACN,OAAO,SAAS,CAAC;KAClB;AACH,CAAC;AAND,8CAMC;AAED,SAAgB,cAAc,CAAC,IAAY,EAAE,UAAwB;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtG,MAAM,QAAQ,GAAG,CAAC,MAAmB,EAAE,EAAE;QACvC,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IAEF,IAAI,QAAQ,CAAC,cAAW,CAAC,SAAS,CAAC,EAAE;QACnC,MAAM,EAAE,GAAG,IAAA,kBAAW,EAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACrF,OAAO;YACL,IAAI,EAAE,cAAW,CAAC,SAAS;YAC3B,EAAE,EAAE,EAAE;YACN,MAAM,EAAE,GAAG,EAAE,CAAC,IAAA,kBAAW,EAAC,cAAW,CAAC,SAAS,EAAE,EAAE,CAAC;SACrD,CAAC;KACH;SAAM,IAAI,QAAQ,CAAC,cAAW,CAAC,IAAI,CAAC,EAAE;QACrC,MAAM,EAAE,GAAG,IAAA,kBAAW,EAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACrF,OAAO;YACL,IAAI,EAAE,cAAW,CAAC,IAAI;YACtB,EAAE,EAAE,EAAE;YACN,MAAM,EAAE,GAAG,EAAE,CAAC,IAAA,kBAAW,EAAC,cAAW,CAAC,IAAI,EAAE,EAAE,CAAC;SAChD,CAAC;KACH;SAAM,IAAI,QAAQ,CAAC,cAAW,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,cAAW,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,cAAW,CAAC,OAAO,CAAC,EAAE;QACxG,MAAM,OAAO,GAAG,IAAA,YAAS,EAAC,MAAM,CAAC,CAAC;QAElC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAY,CAAC,OAAO,CAAC,EAAE,KAAe,CAAC;QAC/E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAe,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAY,CAAC,MAAM,CAAC,EAAE,KAAe,CAAC;QAClF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAY,CAAC,IAAI,CAAC,EAAE,KAAe,CAAC;QAE9E,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,OAAO,MAAM,CAAC,CAAC,kBAAkB;QACnC,CAAC,CAAC;QACF,IAAI,QAAQ,CAAC,cAAW,CAAC,OAAO,CAAC,EAAE;YACjC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;YACrF,OAAO;gBACL,IAAI,EAAE,cAAW,CAAC,OAAO;gBACzB,EAAE;gBACF,MAAM;gBACN,IAAI;gBACJ,MAAM;gBACN,MAAM;aACP,CAAC;SACH;aAAM,IAAI,QAAQ,CAAC,cAAW,CAAC,KAAK,CAAC,EAAE;YACtC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;YACrF,OAAO;gBACL,IAAI,EAAE,cAAW,CAAC,KAAK;gBACvB,EAAE;gBACF,MAAM;gBACN,IAAI;gBACJ,MAAM;gBACN,MAAM;aACP,CAAC;SACH;aAAM,IAAI,QAAQ,CAAC,cAAW,CAAC,OAAO,CAAC,EAAE;YACxC,OAAO;gBACL,IAAI,EAAE,cAAW,CAAC,OAAO;gBACzB,EAAE;gBACF,MAAM;gBACN,IAAI;gBACJ,MAAM;gBACN,MAAM;aACP,CAAC;SACH;KACF;SAAM,IAAI,UAAU,EAAE;QACrB,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,GAAG,EAAE,CAAC,IAAA,kBAAW,EAAC,UAAU,EAAE,IAAI,CAAC;SAC5C,CAAC;KACH;IACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;AACxC,CAAC;AAxED,wCAwEC"} \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.d.ts b/packages/system/dist/NostrSystem.d.ts new file mode 100644 index 00000000..c684a9be --- /dev/null +++ b/packages/system/dist/NostrSystem.d.ts @@ -0,0 +1,75 @@ +import ExternalStore from "./ExternalStore"; +import { NostrEvent, TaggedRawEvent } from "./Nostr"; +import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { Query } from "./Query"; +import { RelayCache } from "./GossipModel"; +import { NoteStore } from "./NoteCollection"; +import { BuiltRawReqFilter, RequestBuilder } from "./RequestBuilder"; +import { SystemInterface, SystemSnapshot } from "."; +/** + * Manages nostr content retrieval system + */ +export declare class NostrSystem extends ExternalStore implements SystemInterface { + #private; + /** + * All active queries + */ + Queries: Map; + /** + * Handler function for NIP-42 + */ + HandleAuth?: AuthHandler; + constructor(relayCache: RelayCache); + get Sockets(): ConnectionStateSnapshot[]; + /** + * Connect to a NOSTR relay if not already connected + */ + ConnectToRelay(address: string, options: RelaySettings): Promise; + OnRelayDisconnect(id: string): void; + OnEndOfStoredEvents(c: Readonly, sub: string): void; + OnEvent(sub: string, ev: TaggedRawEvent): void; + /** + * + * @param address Relay address URL + */ + ConnectEphemeralRelay(address: string): Promise; + /** + * Disconnect from a relay + */ + DisconnectRelay(address: string): void; + GetQuery(id: string): Query | undefined; + Query(type: { + new (): T; + }, req: RequestBuilder): Query; + SendQuery(q: Query, qSend: BuiltRawReqFilter): Promise<{ + readonly id: string; + readonly start: number; + sent?: number | undefined; + eose?: number | undefined; + close?: number | undefined; + "__#9@#wasForceClosed": boolean; + readonly "__#9@#fnClose": (id: string) => void; + readonly "__#9@#fnProgress": () => void; + readonly relay: string; + readonly filters: import("./Nostr").ReqFilter[]; + readonly connId: string; + sentToRelay(): void; + gotEose(): void; + forceEose(): void; + sendClose(): void; + readonly queued: number; + readonly runtime: number; + readonly responseTime: number; + readonly finished: boolean; + }[]>; + /** + * Send events to writable relays + */ + BroadcastEvent(ev: NostrEvent): void; + /** + * Write an event to a relay then disconnect + */ + WriteOnceToRelay(address: string, ev: NostrEvent): Promise; + takeSnapshot(): SystemSnapshot; +} +//# sourceMappingURL=NostrSystem.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.d.ts.map b/packages/system/dist/NostrSystem.d.ts.map new file mode 100644 index 00000000..6cfd8efc --- /dev/null +++ b/packages/system/dist/NostrSystem.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrSystem.d.ts","sourceRoot":"","sources":["../src/NostrSystem.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC/F,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,GAAG,CAAC;AAEpD;;GAEG;AACH,qBAAa,WAAY,SAAQ,aAAa,CAAC,cAAc,CAAE,YAAW,eAAe;;IAMvF;;OAEG;IACH,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAa;IAExC;;OAEG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC;gBAKb,UAAU,EAAE,UAAU;IAMlC,IAAI,OAAO,IAAI,uBAAuB,EAAE,CAEvC;IAED;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAmB5D,iBAAiB,CAAC,EAAE,EAAE,MAAM;IAM5B,mBAAmB,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,MAAM;IAMxD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc;IAMvC;;;OAGG;IACG,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAiB7E;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM;IAQ/B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIvC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE;QAAE,QAAQ,CAAC,CAAA;KAAE,EAAE,GAAG,EAAE,cAAc,GAAG,KAAK;IAiCrE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;IAmClD;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,UAAU;IAM7B;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU;IAetD,YAAY,IAAI,cAAc;CA2B/B"} \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.js b/packages/system/dist/NostrSystem.js new file mode 100644 index 00000000..305b539d --- /dev/null +++ b/packages/system/dist/NostrSystem.js @@ -0,0 +1,237 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _NostrSystem_instances, _NostrSystem_sockets, _NostrSystem_log, _NostrSystem_relayCache, _NostrSystem_cleanup; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NostrSystem = void 0; +const debug_1 = __importDefault(require("debug")); +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +const Connection_1 = require("./Connection"); +const Query_1 = require("./Query"); +const Util_1 = require("./Util"); +/** + * Manages nostr content retrieval system + */ +class NostrSystem extends ExternalStore_1.default { + constructor(relayCache) { + super(); + _NostrSystem_instances.add(this); + /** + * All currently connected websockets + */ + _NostrSystem_sockets.set(this, new Map()); + /** + * All active queries + */ + this.Queries = new Map(); + _NostrSystem_log.set(this, (0, debug_1.default)("System")); + _NostrSystem_relayCache.set(this, void 0); + __classPrivateFieldSet(this, _NostrSystem_relayCache, relayCache, "f"); + __classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this); + } + get Sockets() { + return [...__classPrivateFieldGet(this, _NostrSystem_sockets, "f").values()].map(a => a.snapshot()); + } + /** + * Connect to a NOSTR relay if not already connected + */ + async ConnectToRelay(address, options) { + try { + const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address)); + if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) { + const c = new Connection_1.Connection(addr, options, this.HandleAuth?.bind(this)); + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c); + c.OnEvent = (s, e) => this.OnEvent(s, e); + c.OnEose = s => this.OnEndOfStoredEvents(c, s); + c.OnDisconnect = id => this.OnRelayDisconnect(id); + await c.Connect(); + } + else { + // update settings if already connected + (0, Util_1.unwrap)(__classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(addr)).Settings = options; + } + } + catch (e) { + console.error(e); + } + } + OnRelayDisconnect(id) { + for (const [, q] of this.Queries) { + q.connectionLost(id); + } + } + OnEndOfStoredEvents(c, sub) { + for (const [, v] of this.Queries) { + v.eose(sub, c); + } + } + OnEvent(sub, ev) { + for (const [, v] of this.Queries) { + v.onEvent(sub, ev); + } + } + /** + * + * @param address Relay address URL + */ + async ConnectEphemeralRelay(address) { + try { + const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address)); + if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) { + const c = new Connection_1.Connection(addr, { read: true, write: false }, this.HandleAuth?.bind(this), true); + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c); + c.OnEvent = (s, e) => this.OnEvent(s, e); + c.OnEose = s => this.OnEndOfStoredEvents(c, s); + c.OnDisconnect = id => this.OnRelayDisconnect(id); + await c.Connect(); + return c; + } + } + catch (e) { + console.error(e); + } + } + /** + * Disconnect from a relay + */ + DisconnectRelay(address) { + const c = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(address); + if (c) { + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").delete(address); + c.Close(); + } + } + GetQuery(id) { + return this.Queries.get(id); + } + Query(type, req) { + const existing = this.Queries.get(req.id); + if (existing) { + const filters = !req.options?.skipDiff + ? req.buildDiff(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f"), existing.filters) + : req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f")); + if (filters.length === 0 && !!req.options?.skipDiff) { + return existing; + } + else { + for (const subQ of filters) { + this.SendQuery(existing, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O from: %O", req.id, v.id, v.filters, existing.filters))); + } + this.notifyChange(); + return existing; + } + } + else { + const store = new type(); + const filters = req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f")); + const q = new Query_1.Query(req.id, store, req.options?.leaveOpen); + this.Queries.set(req.id, q); + for (const subQ of filters) { + this.SendQuery(q, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O", req.id, v.id, v.filters))); + } + this.notifyChange(); + return q; + } + } + async SendQuery(q, qSend) { + if (qSend.relay) { + __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Sending query to %s %O", qSend.relay, qSend); + const s = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(qSend.relay); + if (s) { + const qt = q.sendToRelay(s, qSend); + if (qt) { + return [qt]; + } + } + else { + const nc = await this.ConnectEphemeralRelay(qSend.relay); + if (nc) { + const qt = q.sendToRelay(nc, qSend); + if (qt) { + return [qt]; + } + } + else { + console.warn("Failed to connect to new relay for:", qSend.relay, q); + } + } + } + else { + const ret = []; + for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) { + if (!s.Ephemeral) { + const qt = q.sendToRelay(s, qSend); + if (qt) { + ret.push(qt); + } + } + } + return ret; + } + return []; + } + /** + * Send events to writable relays + */ + BroadcastEvent(ev) { + for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) { + s.SendEvent(ev); + } + } + /** + * Write an event to a relay then disconnect + */ + async WriteOnceToRelay(address, ev) { + return new Promise((resolve, reject) => { + const c = new Connection_1.Connection(address, { write: true, read: false }, this.HandleAuth, true); + const t = setTimeout(reject, 5000); + c.OnConnected = async () => { + clearTimeout(t); + await c.SendAsync(ev); + c.Close(); + resolve(); + }; + c.Connect(); + }); + } + takeSnapshot() { + return { + queries: [...this.Queries.values()].map(a => { + return { + id: a.id, + filters: a.filters, + subFilters: [], + }; + }), + }; + } +} +exports.NostrSystem = NostrSystem; +_NostrSystem_sockets = new WeakMap(), _NostrSystem_log = new WeakMap(), _NostrSystem_relayCache = new WeakMap(), _NostrSystem_instances = new WeakSet(), _NostrSystem_cleanup = function _NostrSystem_cleanup() { + let changed = false; + for (const [k, v] of this.Queries) { + if (v.canRemove()) { + v.sendClose(); + this.Queries.delete(k); + __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Deleted query %s", k); + changed = true; + } + } + if (changed) { + this.notifyChange(); + } + setTimeout(() => __classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this), 1000); +}; +//# sourceMappingURL=NostrSystem.js.map \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.js.map b/packages/system/dist/NostrSystem.js.map new file mode 100644 index 00000000..52f75a20 --- /dev/null +++ b/packages/system/dist/NostrSystem.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrSystem.js","sourceRoot":"","sources":["../src/NostrSystem.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.d.ts b/packages/system/dist/NoteCollection.d.ts new file mode 100644 index 00000000..47f8c80c --- /dev/null +++ b/packages/system/dist/NoteCollection.d.ts @@ -0,0 +1,91 @@ +import { TaggedRawEvent } from "."; +export interface StoreSnapshot { + data: TSnapshot | undefined; + clear: () => void; + loading: () => boolean; + add: (ev: Readonly | Readonly>) => void; +} +export declare const EmptySnapshot: StoreSnapshot; +export type NoteStoreSnapshotData = Readonly> | Readonly; +export type NoteStoreHook = () => void; +export type NoteStoreHookRelease = () => void; +export type OnEventCallback = (e: Readonly>) => void; +export type OnEventCallbackRelease = () => void; +export type OnEoseCallback = (c: string) => void; +export type OnEoseCallbackRelease = () => void; +/** + * Generic note store interface + */ +export declare abstract class NoteStore { + abstract add(ev: Readonly | Readonly>): void; + abstract clear(): void; + abstract hook(cb: NoteStoreHook): NoteStoreHookRelease; + abstract getSnapshotData(): NoteStoreSnapshotData | undefined; + abstract onEvent(cb: OnEventCallback): OnEventCallbackRelease; + abstract get snapshot(): StoreSnapshot; + abstract get loading(): boolean; + abstract set loading(v: boolean); +} +export declare abstract class HookedNoteStore implements NoteStore { + #private; + get snapshot(): StoreSnapshot; + get loading(): boolean; + set loading(v: boolean); + abstract add(ev: Readonly | Readonly>): void; + abstract clear(): void; + hook(cb: NoteStoreHook): NoteStoreHookRelease; + getSnapshotData(): TSnapshot | undefined; + onEvent(cb: OnEventCallback): OnEventCallbackRelease; + protected abstract takeSnapshot(): TSnapshot | undefined; + protected onChange(changes: Readonly>): void; +} +/** + * A simple flat container of events with no duplicates + */ +export declare class FlatNoteStore extends HookedNoteStore>> { + #private; + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): TaggedRawEvent[]; +} +/** + * A note store that holds a single replaceable event for a given user defined key generator function + */ +export declare class KeyedReplaceableNoteStore extends HookedNoteStore>> { + #private; + constructor(fn: (ev: TaggedRawEvent) => string); + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): TaggedRawEvent[]; +} +/** + * A note store that holds a single replaceable event + */ +export declare class ReplaceableNoteStore extends HookedNoteStore> { + #private; + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): Readonly<{ + relays: string[]; + id: string; + pubkey: string; + created_at: number; + kind: number; + tags: string[][]; + content: string; + sig: string; + }> | undefined; +} +/** + * A note store that holds a single replaceable event per pubkey + */ +export declare class PubkeyReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor(); +} +/** + * A note store that holds a single replaceable event per "pubkey-dtag" + */ +export declare class ParameterizedReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor(); +} +//# sourceMappingURL=NoteCollection.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.d.ts.map b/packages/system/dist/NoteCollection.d.ts.map new file mode 100644 index 00000000..ffe731e5 --- /dev/null +++ b/packages/system/dist/NoteCollection.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NoteCollection.d.ts","sourceRoot":"","sources":["../src/NoteCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.js b/packages/system/dist/NoteCollection.js new file mode 100644 index 00000000..70e7376c --- /dev/null +++ b/packages/system/dist/NoteCollection.js @@ -0,0 +1,240 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _HookedNoteStore_instances, _HookedNoteStore_hooks, _HookedNoteStore_eventHooks, _HookedNoteStore_loading, _HookedNoteStore_storeSnapshot, _HookedNoteStore_needsSnapshot, _HookedNoteStore_nextNotifyTimer, _HookedNoteStore_updateSnapshot, _FlatNoteStore_events, _FlatNoteStore_ids, _KeyedReplaceableNoteStore_keyFn, _KeyedReplaceableNoteStore_events, _ReplaceableNoteStore_event; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ParameterizedReplaceableNoteStore = exports.PubkeyReplaceableNoteStore = exports.ReplaceableNoteStore = exports.KeyedReplaceableNoteStore = exports.FlatNoteStore = exports.HookedNoteStore = exports.NoteStore = exports.EmptySnapshot = void 0; +const Util_1 = require("./Util"); +exports.EmptySnapshot = { + data: undefined, + clear: () => { + // empty + }, + loading: () => true, + add: () => { + // empty + }, +}; +/** + * Generic note store interface + */ +class NoteStore { +} +exports.NoteStore = NoteStore; +class HookedNoteStore { + constructor() { + _HookedNoteStore_instances.add(this); + _HookedNoteStore_hooks.set(this, []); + _HookedNoteStore_eventHooks.set(this, []); + _HookedNoteStore_loading.set(this, true); + _HookedNoteStore_storeSnapshot.set(this, { + clear: () => this.clear(), + loading: () => this.loading, + add: ev => this.add(ev), + data: undefined, + }); + _HookedNoteStore_needsSnapshot.set(this, true); + _HookedNoteStore_nextNotifyTimer.set(this, void 0); + } + get snapshot() { + __classPrivateFieldGet(this, _HookedNoteStore_instances, "m", _HookedNoteStore_updateSnapshot).call(this); + return __classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f"); + } + get loading() { + return __classPrivateFieldGet(this, _HookedNoteStore_loading, "f"); + } + set loading(v) { + __classPrivateFieldSet(this, _HookedNoteStore_loading, v, "f"); + this.onChange([]); + } + hook(cb) { + __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").push(cb); + return () => { + const idx = __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").findIndex(a => a === cb); + __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").splice(idx, 1); + }; + } + getSnapshotData() { + __classPrivateFieldGet(this, _HookedNoteStore_instances, "m", _HookedNoteStore_updateSnapshot).call(this); + return __classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f").data; + } + onEvent(cb) { + const existing = __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").find(a => a === cb); + if (!existing) { + __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").push(cb); + return () => { + const idx = __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").findIndex(a => a === cb); + __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").splice(idx, 1); + }; + } + return () => { + //noop + }; + } + onChange(changes) { + __classPrivateFieldSet(this, _HookedNoteStore_needsSnapshot, true, "f"); + if (!__classPrivateFieldGet(this, _HookedNoteStore_nextNotifyTimer, "f")) { + __classPrivateFieldSet(this, _HookedNoteStore_nextNotifyTimer, setTimeout(() => { + __classPrivateFieldSet(this, _HookedNoteStore_nextNotifyTimer, undefined, "f"); + for (const hk of __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f")) { + hk(); + } + }, 500), "f"); + } + if (changes.length > 0) { + for (const hkE of __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f")) { + hkE(changes); + } + } + } +} +exports.HookedNoteStore = HookedNoteStore; +_HookedNoteStore_hooks = new WeakMap(), _HookedNoteStore_eventHooks = new WeakMap(), _HookedNoteStore_loading = new WeakMap(), _HookedNoteStore_storeSnapshot = new WeakMap(), _HookedNoteStore_needsSnapshot = new WeakMap(), _HookedNoteStore_nextNotifyTimer = new WeakMap(), _HookedNoteStore_instances = new WeakSet(), _HookedNoteStore_updateSnapshot = function _HookedNoteStore_updateSnapshot() { + if (__classPrivateFieldGet(this, _HookedNoteStore_needsSnapshot, "f")) { + __classPrivateFieldSet(this, _HookedNoteStore_storeSnapshot, { + ...__classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f"), + data: this.takeSnapshot(), + }, "f"); + __classPrivateFieldSet(this, _HookedNoteStore_needsSnapshot, false, "f"); + } +}; +/** + * A simple flat container of events with no duplicates + */ +class FlatNoteStore extends HookedNoteStore { + constructor() { + super(...arguments); + _FlatNoteStore_events.set(this, []); + _FlatNoteStore_ids.set(this, new Set()); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + if (!__classPrivateFieldGet(this, _FlatNoteStore_ids, "f").has(a.id)) { + __classPrivateFieldGet(this, _FlatNoteStore_events, "f").push(a); + __classPrivateFieldGet(this, _FlatNoteStore_ids, "f").add(a.id); + changes.push(a); + } + else { + const existing = __classPrivateFieldGet(this, _FlatNoteStore_events, "f").find(b => b.id === a.id); + if (existing) { + existing.relays = (0, Util_1.appendDedupe)(existing.relays, a.relays); + } + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldSet(this, _FlatNoteStore_events, [], "f"); + __classPrivateFieldGet(this, _FlatNoteStore_ids, "f").clear(); + this.onChange([]); + } + takeSnapshot() { + return [...__classPrivateFieldGet(this, _FlatNoteStore_events, "f")]; + } +} +exports.FlatNoteStore = FlatNoteStore; +_FlatNoteStore_events = new WeakMap(), _FlatNoteStore_ids = new WeakMap(); +/** + * A note store that holds a single replaceable event for a given user defined key generator function + */ +class KeyedReplaceableNoteStore extends HookedNoteStore { + constructor(fn) { + super(); + _KeyedReplaceableNoteStore_keyFn.set(this, void 0); + _KeyedReplaceableNoteStore_events.set(this, new Map()); + __classPrivateFieldSet(this, _KeyedReplaceableNoteStore_keyFn, fn, "f"); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + const keyOnEvent = __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_keyFn, "f").call(this, a); + const existingCreated = __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").get(keyOnEvent)?.created_at ?? 0; + if (a.created_at > existingCreated) { + __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").set(keyOnEvent, a); + changes.push(a); + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").clear(); + this.onChange([]); + } + takeSnapshot() { + return [...__classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").values()]; + } +} +exports.KeyedReplaceableNoteStore = KeyedReplaceableNoteStore; +_KeyedReplaceableNoteStore_keyFn = new WeakMap(), _KeyedReplaceableNoteStore_events = new WeakMap(); +/** + * A note store that holds a single replaceable event + */ +class ReplaceableNoteStore extends HookedNoteStore { + constructor() { + super(...arguments); + _ReplaceableNoteStore_event.set(this, void 0); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + const existingCreated = __classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f")?.created_at ?? 0; + if (a.created_at > existingCreated) { + __classPrivateFieldSet(this, _ReplaceableNoteStore_event, a, "f"); + changes.push(a); + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldSet(this, _ReplaceableNoteStore_event, undefined, "f"); + this.onChange([]); + } + takeSnapshot() { + if (__classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f")) { + return Object.freeze({ ...__classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f") }); + } + } +} +exports.ReplaceableNoteStore = ReplaceableNoteStore; +_ReplaceableNoteStore_event = new WeakMap(); +/** + * A note store that holds a single replaceable event per pubkey + */ +class PubkeyReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor() { + super(e => e.pubkey); + } +} +exports.PubkeyReplaceableNoteStore = PubkeyReplaceableNoteStore; +/** + * A note store that holds a single replaceable event per "pubkey-dtag" + */ +class ParameterizedReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor() { + super(ev => { + const dTag = (0, Util_1.findTag)(ev, "d"); + return `${ev.pubkey}-${dTag}`; + }); + } +} +exports.ParameterizedReplaceableNoteStore = ParameterizedReplaceableNoteStore; +//# sourceMappingURL=NoteCollection.js.map \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.js.map b/packages/system/dist/NoteCollection.js.map new file mode 100644 index 00000000..b9630ff9 --- /dev/null +++ b/packages/system/dist/NoteCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NoteCollection.js","sourceRoot":"","sources":["../src/NoteCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.d.ts b/packages/system/dist/ProfileCache.d.ts new file mode 100644 index 00000000..87f4e53f --- /dev/null +++ b/packages/system/dist/ProfileCache.d.ts @@ -0,0 +1,20 @@ +import { HexKey, SystemInterface, TaggedRawEvent } from "."; +import { CacheStore, MetadataCache } from "./cache"; +export declare class ProfileLoaderService { + #private; + /** + * List of pubkeys to fetch metadata for + */ + WantsMetadata: Set; + constructor(system: SystemInterface, cache: CacheStore); + /** + * Request profile metadata for a set of pubkeys + */ + TrackMetadata(pk: HexKey | Array): void; + /** + * Stop tracking metadata for a set of pubkeys + */ + UntrackMetadata(pk: HexKey | Array): void; + onProfileEvent(e: Readonly): Promise; +} +//# sourceMappingURL=ProfileCache.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.d.ts.map b/packages/system/dist/ProfileCache.d.ts.map new file mode 100644 index 00000000..acbcf017 --- /dev/null +++ b/packages/system/dist/ProfileCache.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ProfileCache.d.ts","sourceRoot":"","sources":["../src/ProfileCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,eAAe,EAAE,cAAc,EAA8C,MAAM,GAAG,CAAC;AAEnH,OAAO,EAAE,UAAU,EAAqB,aAAa,EAAE,MAAM,SAAS,CAAC;AAIvE,qBAAa,oBAAoB;;IAI/B;;OAEG;IACH,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;gBAI3B,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC;IAMrE;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAUxC;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAQpC,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;CA4EjD"} \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.js b/packages/system/dist/ProfileCache.js new file mode 100644 index 00000000..98105241 --- /dev/null +++ b/packages/system/dist/ProfileCache.js @@ -0,0 +1,129 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _ProfileLoaderService_instances, _ProfileLoaderService_system, _ProfileLoaderService_cache, _ProfileLoaderService_log, _ProfileLoaderService_FetchMetadata; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProfileLoaderService = void 0; +const _1 = require("."); +const Const_1 = require("./Const"); +const cache_1 = require("./cache"); +const Util_1 = require("./Util"); +const debug_1 = __importDefault(require("debug")); +class ProfileLoaderService { + constructor(system, cache) { + _ProfileLoaderService_instances.add(this); + _ProfileLoaderService_system.set(this, void 0); + _ProfileLoaderService_cache.set(this, void 0); + /** + * List of pubkeys to fetch metadata for + */ + this.WantsMetadata = new Set(); + _ProfileLoaderService_log.set(this, (0, debug_1.default)("ProfileCache")); + __classPrivateFieldSet(this, _ProfileLoaderService_system, system, "f"); + __classPrivateFieldSet(this, _ProfileLoaderService_cache, cache, "f"); + __classPrivateFieldGet(this, _ProfileLoaderService_instances, "m", _ProfileLoaderService_FetchMetadata).call(this); + } + /** + * Request profile metadata for a set of pubkeys + */ + TrackMetadata(pk) { + const bufferNow = []; + for (const p of Array.isArray(pk) ? pk : [pk]) { + if (p.length > 0 && this.WantsMetadata.add(p)) { + bufferNow.push(p); + } + } + __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").buffer(bufferNow); + } + /** + * Stop tracking metadata for a set of pubkeys + */ + UntrackMetadata(pk) { + for (const p of Array.isArray(pk) ? pk : [pk]) { + if (p.length > 0) { + this.WantsMetadata.delete(p); + } + } + } + async onProfileEvent(e) { + const profile = (0, cache_1.mapEventToProfile)(e); + if (profile) { + await __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").update(profile); + } + } +} +exports.ProfileLoaderService = ProfileLoaderService; +_ProfileLoaderService_system = new WeakMap(), _ProfileLoaderService_cache = new WeakMap(), _ProfileLoaderService_log = new WeakMap(), _ProfileLoaderService_instances = new WeakSet(), _ProfileLoaderService_FetchMetadata = async function _ProfileLoaderService_FetchMetadata() { + const missingFromCache = await __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").buffer([...this.WantsMetadata]); + const expire = (0, Util_1.unixNowMs)() - Const_1.ProfileCacheExpire; + const expired = [...this.WantsMetadata] + .filter(a => !missingFromCache.includes(a)) + .filter(a => (__classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").getFromCache(a)?.loaded ?? 0) < expire); + const missing = new Set([...missingFromCache, ...expired]); + if (missing.size > 0) { + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Wants profiles: %d missing, %d expired", missingFromCache.length, expired.length); + const sub = new _1.RequestBuilder("profiles"); + sub + .withOptions({ + skipDiff: true, + }) + .withFilter() + .kinds([_1.EventKind.SetMetadata]) + .authors([...missing]); + const newProfiles = new Set(); + const q = __classPrivateFieldGet(this, _ProfileLoaderService_system, "f").Query(_1.PubkeyReplaceableNoteStore, sub); + const feed = q?.feed ?? new _1.PubkeyReplaceableNoteStore(); + // never release this callback, it will stop firing anyway after eose + const releaseOnEvent = feed.onEvent(async (e) => { + for (const pe of e) { + newProfiles.add(pe.id); + await this.onProfileEvent(pe); + } + }); + const results = await new Promise(resolve => { + let timeout = undefined; + const release = feed.hook(() => { + if (!feed.loading) { + clearTimeout(timeout); + resolve(feed.getSnapshotData() ?? []); + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Profiles finished: %s", sub.id); + release(); + } + }); + timeout = setTimeout(() => { + release(); + resolve(feed.getSnapshotData() ?? []); + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Profiles timeout: %s", sub.id); + }, 5000); + }); + releaseOnEvent(); + const couldNotFetch = [...missing].filter(a => !results.some(b => b.pubkey === a)); + if (couldNotFetch.length > 0) { + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "No profiles: %o", couldNotFetch); + const empty = couldNotFetch.map(a => __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").update({ + pubkey: a, + loaded: (0, Util_1.unixNowMs)() - Const_1.ProfileCacheExpire + 5000, + created: 69, + })); + await Promise.all(empty); + } + // When we fetch an expired profile and its the same as what we already have + // onEvent is not fired and the loaded timestamp never gets updated + const expiredSame = results.filter(a => !newProfiles.has(a.id) && expired.includes(a.pubkey)); + await Promise.all(expiredSame.map(v => this.onProfileEvent(v))); + } + setTimeout(() => __classPrivateFieldGet(this, _ProfileLoaderService_instances, "m", _ProfileLoaderService_FetchMetadata).call(this), 500); +}; +//# sourceMappingURL=ProfileCache.js.map \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.js.map b/packages/system/dist/ProfileCache.js.map new file mode 100644 index 00000000..2722da34 --- /dev/null +++ b/packages/system/dist/ProfileCache.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ProfileCache.js","sourceRoot":"","sources":["../src/ProfileCache.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Query.d.ts b/packages/system/dist/Query.d.ts new file mode 100644 index 00000000..03469640 --- /dev/null +++ b/packages/system/dist/Query.d.ts @@ -0,0 +1,86 @@ +import { Connection, ReqFilter, TaggedRawEvent } from "."; +import { NoteStore } from "./NoteCollection"; +import { BuiltRawReqFilter } from "./RequestBuilder"; +/** + * Tracing for relay query status + */ +declare class QueryTrace { + #private; + readonly relay: string; + readonly filters: Array; + readonly connId: string; + readonly id: string; + readonly start: number; + sent?: number; + eose?: number; + close?: number; + constructor(relay: string, filters: Array, connId: string, fnClose: (id: string) => void, fnProgress: () => void); + sentToRelay(): void; + gotEose(): void; + forceEose(): void; + sendClose(): void; + /** + * Time spent in queue + */ + get queued(): number; + /** + * Total query runtime + */ + get runtime(): number; + /** + * Total time spent waiting for relay to respond + */ + get responseTime(): number; + /** + * If tracing is finished, we got EOSE or timeout + */ + get finished(): boolean; +} +export interface QueryBase { + /** + * Uniquie ID of this query + */ + id: string; + /** + * The query payload (REQ filters) + */ + filters: Array; + /** + * List of relays to send this query to + */ + relays?: Array; +} +/** + * Active or queued query on the system + */ +export declare class Query implements QueryBase { + #private; + /** + * Uniquie ID of this query + */ + id: string; + constructor(id: string, feed: NoteStore, leaveOpen?: boolean); + canRemove(): boolean; + /** + * Recompute the complete set of compressed filters from all query traces + */ + get filters(): ReqFilter[]; + get feed(): NoteStore; + onEvent(sub: string, e: TaggedRawEvent): void; + /** + * This function should be called when this Query object and FeedStore is no longer needed + */ + cancel(): void; + uncancel(): void; + cleanup(): void; + sendToRelay(c: Connection, subq: BuiltRawReqFilter): QueryTrace | undefined; + connectionLost(id: string): void; + sendClose(): void; + eose(sub: string, conn: Readonly): void; + /** + * Get the progress to EOSE, can be used to determine when we should load more content + */ + get progress(): number; +} +export {}; +//# sourceMappingURL=Query.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Query.d.ts.map b/packages/system/dist/Query.d.ts.map new file mode 100644 index 00000000..e3da2f8c --- /dev/null +++ b/packages/system/dist/Query.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../src/Query.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAQ,cAAc,EAAE,MAAM,GAAG,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;GAEG;AACH,cAAM,UAAU;;IAWZ,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAZzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;gBAMJ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,EACzB,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,EAC7B,UAAU,EAAE,MAAM,IAAI;IAQxB,WAAW;IAKX,OAAO;IAKP,SAAS;IAOT,SAAS;IAMT;;OAEG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,OAAO,WAEV;IAED;;OAEG;IACH,IAAI,YAAY,WAEf;IAED;;OAEG;IACH,IAAI,QAAQ,YAEX;CACF;AAED,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAE1B;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS;;IACrC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;gBA8BC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO;IAO5D,SAAS;IAIT;;OAEG;IACH,IAAI,OAAO,gBAEV;IAED,IAAI,IAAI,cAEP;IAED,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc;IAStC;;OAEG;IACH,MAAM;IAIN,QAAQ;IAIR,OAAO;IAIP,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,iBAAiB;IAOlD,cAAc,CAAC,EAAE,EAAE,MAAM;IAIzB,SAAS;IAOT,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC;IAQ5C;;OAEG;IACH,IAAI,QAAQ,WAMX;CA6DF"} \ No newline at end of file diff --git a/packages/system/dist/Query.js b/packages/system/dist/Query.js new file mode 100644 index 00000000..78b291fa --- /dev/null +++ b/packages/system/dist/Query.js @@ -0,0 +1,228 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _QueryTrace_wasForceClosed, _QueryTrace_fnClose, _QueryTrace_fnProgress, _Query_instances, _Query_tracing, _Query_leaveOpen, _Query_cancelAt, _Query_checkTrace, _Query_feed, _Query_log, _Query_allFilters, _Query_onProgress, _Query_stopCheckTraces, _Query_checkTraces, _Query_canSendQuery, _Query_sendQueryInternal, _Query_reComputeFilters; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Query = void 0; +const uuid_1 = require("uuid"); +const debug_1 = __importDefault(require("debug")); +const _1 = require("."); +const Util_1 = require("./Util"); +const RequestMerger_1 = require("./RequestMerger"); +const RequestExpander_1 = require("./RequestExpander"); +/** + * Tracing for relay query status + */ +class QueryTrace { + constructor(relay, filters, connId, fnClose, fnProgress) { + this.relay = relay; + this.filters = filters; + this.connId = connId; + _QueryTrace_wasForceClosed.set(this, false); + _QueryTrace_fnClose.set(this, void 0); + _QueryTrace_fnProgress.set(this, void 0); + this.id = (0, uuid_1.v4)(); + this.start = (0, Util_1.unixNowMs)(); + __classPrivateFieldSet(this, _QueryTrace_fnClose, fnClose, "f"); + __classPrivateFieldSet(this, _QueryTrace_fnProgress, fnProgress, "f"); + } + sentToRelay() { + this.sent = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + gotEose() { + this.eose = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + forceEose() { + this.eose = (0, Util_1.unixNowMs)(); + __classPrivateFieldSet(this, _QueryTrace_wasForceClosed, true, "f"); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + this.sendClose(); + } + sendClose() { + this.close = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnClose, "f").call(this, this.id); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + /** + * Time spent in queue + */ + get queued() { + return (this.sent === undefined ? (0, Util_1.unixNowMs)() : __classPrivateFieldGet(this, _QueryTrace_wasForceClosed, "f") ? (0, Util_1.unwrap)(this.eose) : this.sent) - this.start; + } + /** + * Total query runtime + */ + get runtime() { + return (this.eose === undefined ? (0, Util_1.unixNowMs)() : this.eose) - this.start; + } + /** + * Total time spent waiting for relay to respond + */ + get responseTime() { + return this.finished ? (0, Util_1.unwrap)(this.eose) - (0, Util_1.unwrap)(this.sent) : 0; + } + /** + * If tracing is finished, we got EOSE or timeout + */ + get finished() { + return this.eose !== undefined; + } +} +_QueryTrace_wasForceClosed = new WeakMap(), _QueryTrace_fnClose = new WeakMap(), _QueryTrace_fnProgress = new WeakMap(); +/** + * Active or queued query on the system + */ +class Query { + constructor(id, feed, leaveOpen) { + _Query_instances.add(this); + /** + * Which relays this query has already been executed on + */ + _Query_tracing.set(this, []); + /** + * Leave the query open until its removed + */ + _Query_leaveOpen.set(this, false); + /** + * Time when this query can be removed + */ + _Query_cancelAt.set(this, void 0); + /** + * Timer used to track tracing status + */ + _Query_checkTrace.set(this, void 0); + /** + * Feed object which collects events + */ + _Query_feed.set(this, void 0); + _Query_log.set(this, (0, debug_1.default)("Query")); + _Query_allFilters.set(this, []); + this.id = id; + __classPrivateFieldSet(this, _Query_feed, feed, "f"); + __classPrivateFieldSet(this, _Query_leaveOpen, leaveOpen ?? false, "f"); + __classPrivateFieldGet(this, _Query_instances, "m", _Query_checkTraces).call(this); + } + canRemove() { + return __classPrivateFieldGet(this, _Query_cancelAt, "f") !== undefined && __classPrivateFieldGet(this, _Query_cancelAt, "f") < (0, Util_1.unixNowMs)(); + } + /** + * Recompute the complete set of compressed filters from all query traces + */ + get filters() { + return __classPrivateFieldGet(this, _Query_allFilters, "f"); + } + get feed() { + return __classPrivateFieldGet(this, _Query_feed, "f"); + } + onEvent(sub, e) { + for (const t of __classPrivateFieldGet(this, _Query_tracing, "f")) { + if (t.id === sub) { + this.feed.add(e); + break; + } + } + } + /** + * This function should be called when this Query object and FeedStore is no longer needed + */ + cancel() { + __classPrivateFieldSet(this, _Query_cancelAt, (0, Util_1.unixNowMs)() + 5000, "f"); + } + uncancel() { + __classPrivateFieldSet(this, _Query_cancelAt, undefined, "f"); + } + cleanup() { + __classPrivateFieldGet(this, _Query_instances, "m", _Query_stopCheckTraces).call(this); + } + sendToRelay(c, subq) { + if (!__classPrivateFieldGet(this, _Query_instances, "m", _Query_canSendQuery).call(this, c, subq)) { + return; + } + return __classPrivateFieldGet(this, _Query_instances, "m", _Query_sendQueryInternal).call(this, c, subq); + } + connectionLost(id) { + __classPrivateFieldGet(this, _Query_tracing, "f").filter(a => a.connId == id).forEach(a => a.forceEose()); + } + sendClose() { + for (const qt of __classPrivateFieldGet(this, _Query_tracing, "f")) { + qt.sendClose(); + } + this.cleanup(); + } + eose(sub, conn) { + const qt = __classPrivateFieldGet(this, _Query_tracing, "f").find(a => a.id === sub && a.connId === conn.Id); + qt?.gotEose(); + if (!__classPrivateFieldGet(this, _Query_leaveOpen, "f")) { + qt?.sendClose(); + } + } + /** + * Get the progress to EOSE, can be used to determine when we should load more content + */ + get progress() { + const thisProgress = __classPrivateFieldGet(this, _Query_tracing, "f").reduce((acc, v) => (acc += v.finished ? 1 : 0), 0) / __classPrivateFieldGet(this, _Query_tracing, "f").length; + if (isNaN(thisProgress)) { + return 0; + } + return thisProgress; + } +} +exports.Query = Query; +_Query_tracing = new WeakMap(), _Query_leaveOpen = new WeakMap(), _Query_cancelAt = new WeakMap(), _Query_checkTrace = new WeakMap(), _Query_feed = new WeakMap(), _Query_log = new WeakMap(), _Query_allFilters = new WeakMap(), _Query_instances = new WeakSet(), _Query_onProgress = function _Query_onProgress() { + const isFinished = this.progress === 1; + if (this.feed.loading !== isFinished) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "%s loading=%s, progress=%d", this.id, this.feed.loading, this.progress); + this.feed.loading = isFinished; + } +}, _Query_stopCheckTraces = function _Query_stopCheckTraces() { + if (__classPrivateFieldGet(this, _Query_checkTrace, "f")) { + clearInterval(__classPrivateFieldGet(this, _Query_checkTrace, "f")); + } +}, _Query_checkTraces = function _Query_checkTraces() { + __classPrivateFieldGet(this, _Query_instances, "m", _Query_stopCheckTraces).call(this); + __classPrivateFieldSet(this, _Query_checkTrace, setInterval(() => { + for (const v of __classPrivateFieldGet(this, _Query_tracing, "f")) { + if (v.runtime > 5000 && !v.finished) { + v.forceEose(); + } + } + }, 500), "f"); +}, _Query_canSendQuery = function _Query_canSendQuery(c, q) { + if (q.relay && q.relay !== c.Address) { + return false; + } + if (!q.relay && c.Ephemeral) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "Cant send non-specific REQ to ephemeral connection %O %O %O", q, q.relay, c); + return false; + } + if (q.filters.some(a => a.search) && !c.SupportsNip(_1.Nips.Search)) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "Cant send REQ to non-search relay", c.Address); + return false; + } + return true; +}, _Query_sendQueryInternal = function _Query_sendQueryInternal(c, q) { + const qt = new QueryTrace(c.Address, q.filters, c.Id, x => c.CloseReq(x), () => __classPrivateFieldGet(this, _Query_instances, "m", _Query_onProgress).call(this)); + __classPrivateFieldGet(this, _Query_tracing, "f").push(qt); + __classPrivateFieldGet(this, _Query_instances, "m", _Query_reComputeFilters).call(this); + c.QueueReq(["REQ", qt.id, ...q.filters], () => qt.sentToRelay()); + return qt; +}, _Query_reComputeFilters = function _Query_reComputeFilters() { + console.time("reComputeFilters"); + __classPrivateFieldSet(this, _Query_allFilters, (0, RequestMerger_1.flatMerge)(__classPrivateFieldGet(this, _Query_tracing, "f").flatMap(a => a.filters).flatMap(RequestExpander_1.expandFilter)), "f"); + console.timeEnd("reComputeFilters"); +}; +//# sourceMappingURL=Query.js.map \ No newline at end of file diff --git a/packages/system/dist/Query.js.map b/packages/system/dist/Query.js.map new file mode 100644 index 00000000..56d1e707 --- /dev/null +++ b/packages/system/dist/Query.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.js","sourceRoot":"","sources":["../src/Query.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.d.ts b/packages/system/dist/RelayInfo.d.ts new file mode 100644 index 00000000..0ffe9742 --- /dev/null +++ b/packages/system/dist/RelayInfo.d.ts @@ -0,0 +1,17 @@ +export interface RelayInfo { + name?: string; + description?: string; + pubkey?: string; + contact?: string; + supported_nips?: number[]; + software?: string; + version?: string; + limitation?: { + payment_required: boolean; + max_subscriptions: number; + max_filters: number; + max_event_tags: number; + auth_required: boolean; + }; +} +//# sourceMappingURL=RelayInfo.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.d.ts.map b/packages/system/dist/RelayInfo.d.ts.map new file mode 100644 index 00000000..c52f7495 --- /dev/null +++ b/packages/system/dist/RelayInfo.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RelayInfo.d.ts","sourceRoot":"","sources":["../src/RelayInfo.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QACX,gBAAgB,EAAE,OAAO,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;CACH"} \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.js b/packages/system/dist/RelayInfo.js new file mode 100644 index 00000000..0591ac98 --- /dev/null +++ b/packages/system/dist/RelayInfo.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=RelayInfo.js.map \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.js.map b/packages/system/dist/RelayInfo.js.map new file mode 100644 index 00000000..4fff9c16 --- /dev/null +++ b/packages/system/dist/RelayInfo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RelayInfo.js","sourceRoot":"","sources":["../src/RelayInfo.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.d.ts b/packages/system/dist/RequestBuilder.d.ts new file mode 100644 index 00000000..94ef5649 --- /dev/null +++ b/packages/system/dist/RequestBuilder.d.ts @@ -0,0 +1,93 @@ +import { ReqFilter, u256, HexKey, EventKind } from "."; +import { RelayCache } from "./GossipModel"; +/** + * Which strategy is used when building REQ filters + */ +export declare enum RequestStrategy { + /** + * Use the users default relays to fetch events, + * this is the fallback option when there is no better way to query a given filter set + */ + DefaultRelays = 1, + /** + * Using a cached copy of the authors relay lists NIP-65, split a given set of request filters by pubkey + */ + AuthorsRelays = 2, + /** + * Relay hints are usually provided when using replies + */ + RelayHintedEventIds = 3 +} +/** + * A built REQ filter ready for sending to System + */ +export interface BuiltRawReqFilter { + filters: Array; + relay: string; + strategy: RequestStrategy; +} +export interface RequestBuilderOptions { + leaveOpen?: boolean; + relays?: Array; + /** + * Do not apply diff logic and always use full filters for query + */ + skipDiff?: boolean; +} +/** + * Nostr REQ builder + */ +export declare class RequestBuilder { + #private; + id: string; + constructor(id: string); + get numFilters(): number; + get options(): RequestBuilderOptions | undefined; + withFilter(): RequestFilterBuilder; + withOptions(opt: RequestBuilderOptions): this; + buildRaw(): Array; + build(relays: RelayCache): Array; + /** + * Detects a change in request from a previous set of filters + * @param q All previous filters merged + * @returns + */ + buildDiff(relays: RelayCache, filters: Array): Array; +} +/** + * Builder class for a single request filter + */ +export declare class RequestFilterBuilder { + #private; + get filter(): { + ids?: string[] | undefined; /** + * Relay hints are usually provided when using replies + */ + authors?: string[] | undefined; + kinds?: number[] | undefined; + "#e"?: string[] | undefined; + "#p"?: string[] | undefined; + "#t"?: string[] | undefined; + "#d"?: string[] | undefined; + "#r"?: string[] | undefined; + search?: string | undefined; + since?: number | undefined; + until?: number | undefined; + limit?: number | undefined; + }; + get relayHints(): Map; + ids(ids: Array): this; + id(id: u256, relay?: string): this; + authors(authors?: Array): this; + kinds(kinds?: Array): this; + since(since?: number): this; + until(until?: number): this; + limit(limit?: number): this; + tag(key: "e" | "p" | "d" | "t" | "r", value?: Array): this; + search(keyword?: string): this; + /** + * Build/expand this filter into a set of relay specific queries + */ + build(relays: RelayCache, id: string): Array; +} +//# sourceMappingURL=RequestBuilder.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.d.ts.map b/packages/system/dist/RequestBuilder.d.ts.map new file mode 100644 index 00000000..5b037973 --- /dev/null +++ b/packages/system/dist/RequestBuilder.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestBuilder.d.ts","sourceRoot":"","sources":["../src/RequestBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAGvD,OAAO,EAAE,UAAU,EAA6C,MAAM,eAAe,CAAC;AAGtF;;GAEG;AACH,oBAAY,eAAe;IACzB;;;OAGG;IACH,aAAa,IAAI;IAEjB;;OAEG;IACH,aAAa,IAAI;IAEjB;;OAEG;IACH,mBAAmB,IAAI;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,cAAc;;IACzB,EAAE,EAAE,MAAM,CAAC;gBAIC,EAAE,EAAE,MAAM;IAKtB,IAAI,UAAU,WAEb;IAED,IAAI,OAAO,sCAEV;IAED,UAAU;IAMV,WAAW,CAAC,GAAG,EAAE,qBAAqB;IAQtC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC;IAI5B,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAKnD;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC;CAyCnF;AAED;;GAEG;AACH,qBAAa,oBAAoB;;IAI/B,IAAI,MAAM;oCA3HV;;WAEG;;;;;;;;;;;;MA2HF;IAED,IAAI,UAAU,0BAEb;IAED,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC;IAKpB,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM;IAO3B,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;IAM/B,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAM9B,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;IAM3D,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM;IAMvB;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC;CAuChE"} \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.js b/packages/system/dist/RequestBuilder.js new file mode 100644 index 00000000..b6cdc0b7 --- /dev/null +++ b/packages/system/dist/RequestBuilder.js @@ -0,0 +1,225 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _RequestBuilder_instances, _RequestBuilder_builders, _RequestBuilder_options, _RequestBuilder_groupByRelay, _RequestFilterBuilder_filter, _RequestFilterBuilder_relayHints; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RequestFilterBuilder = exports.RequestBuilder = exports.RequestStrategy = void 0; +const Util_1 = require("./Util"); +const RequestSplitter_1 = require("./RequestSplitter"); +const GossipModel_1 = require("./GossipModel"); +const RequestMerger_1 = require("./RequestMerger"); +/** + * Which strategy is used when building REQ filters + */ +var RequestStrategy; +(function (RequestStrategy) { + /** + * Use the users default relays to fetch events, + * this is the fallback option when there is no better way to query a given filter set + */ + RequestStrategy[RequestStrategy["DefaultRelays"] = 1] = "DefaultRelays"; + /** + * Using a cached copy of the authors relay lists NIP-65, split a given set of request filters by pubkey + */ + RequestStrategy[RequestStrategy["AuthorsRelays"] = 2] = "AuthorsRelays"; + /** + * Relay hints are usually provided when using replies + */ + RequestStrategy[RequestStrategy["RelayHintedEventIds"] = 3] = "RelayHintedEventIds"; +})(RequestStrategy = exports.RequestStrategy || (exports.RequestStrategy = {})); +/** + * Nostr REQ builder + */ +class RequestBuilder { + constructor(id) { + _RequestBuilder_instances.add(this); + _RequestBuilder_builders.set(this, void 0); + _RequestBuilder_options.set(this, void 0); + this.id = id; + __classPrivateFieldSet(this, _RequestBuilder_builders, [], "f"); + } + get numFilters() { + return __classPrivateFieldGet(this, _RequestBuilder_builders, "f").length; + } + get options() { + return __classPrivateFieldGet(this, _RequestBuilder_options, "f"); + } + withFilter() { + const ret = new RequestFilterBuilder(); + __classPrivateFieldGet(this, _RequestBuilder_builders, "f").push(ret); + return ret; + } + withOptions(opt) { + __classPrivateFieldSet(this, _RequestBuilder_options, { + ...__classPrivateFieldGet(this, _RequestBuilder_options, "f"), + ...opt, + }, "f"); + return this; + } + buildRaw() { + return __classPrivateFieldGet(this, _RequestBuilder_builders, "f").map(f => f.filter); + } + build(relays) { + const expanded = __classPrivateFieldGet(this, _RequestBuilder_builders, "f").flatMap(a => a.build(relays, this.id)); + return __classPrivateFieldGet(this, _RequestBuilder_instances, "m", _RequestBuilder_groupByRelay).call(this, expanded); + } + /** + * Detects a change in request from a previous set of filters + * @param q All previous filters merged + * @returns + */ + buildDiff(relays, filters) { + const next = this.buildRaw(); + const diff = (0, RequestSplitter_1.diffFilters)(filters, next); + if (diff.changed) { + return (0, GossipModel_1.splitAllByWriteRelays)(relays, diff.added).map(a => { + return { + strategy: RequestStrategy.AuthorsRelays, + filters: a.filters, + relay: a.relay, + }; + }); + } + return []; + } +} +exports.RequestBuilder = RequestBuilder; +_RequestBuilder_builders = new WeakMap(), _RequestBuilder_options = new WeakMap(), _RequestBuilder_instances = new WeakSet(), _RequestBuilder_groupByRelay = function _RequestBuilder_groupByRelay(expanded) { + const relayMerged = expanded.reduce((acc, v) => { + const existing = acc.get(v.relay); + if (existing) { + existing.push(v); + } + else { + acc.set(v.relay, [v]); + } + return acc; + }, new Map()); + const filtersSquashed = [...relayMerged.values()].map(a => { + return { + filters: (0, RequestMerger_1.mergeSimilar)(a.flatMap(b => b.filters)), + relay: a[0].relay, + strategy: a[0].strategy, + }; + }); + return filtersSquashed; +}; +/** + * Builder class for a single request filter + */ +class RequestFilterBuilder { + constructor() { + _RequestFilterBuilder_filter.set(this, {}); + _RequestFilterBuilder_relayHints.set(this, new Map()); + } + get filter() { + return { ...__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f") }; + } + get relayHints() { + return new Map(__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f")); + } + ids(ids) { + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids, ids); + return this; + } + id(id, relay) { + if (relay) { + __classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").set(id, (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").get(id), [relay])); + } + return this.ids([id]); + } + authors(authors) { + if (!authors) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors, authors); + return this; + } + kinds(kinds) { + if (!kinds) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").kinds = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").kinds, kinds); + return this; + } + since(since) { + if (!since) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").since = since; + return this; + } + until(until) { + if (!until) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").until = until; + return this; + } + limit(limit) { + if (!limit) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").limit = limit; + return this; + } + tag(key, value) { + if (!value) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f")[`#${key}`] = value; + return this; + } + search(keyword) { + if (!keyword) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").search = keyword; + return this; + } + /** + * Build/expand this filter into a set of relay specific queries + */ + build(relays, id) { + // when querying for specific event ids with relay hints + // take the first approach which is to split the filter by relay + if (__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids && __classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").size > 0) { + const relays = (0, Util_1.dedupe)([...__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").values()].flat()); + return relays.map(r => { + return { + filters: [ + { + ...__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f"), + ids: [...__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").entries()].filter(([, v]) => v.includes(r)).map(([k]) => k), + }, + ], + relay: r, + strategy: RequestStrategy.RelayHintedEventIds, + }; + }); + } + // If any authors are set use the gossip model to fetch data for each author + if (__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors) { + const split = (0, GossipModel_1.splitByWriteRelays)(relays, __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f")); + return split.map(a => { + return { + filters: [a.filter], + relay: a.relay, + strategy: RequestStrategy.AuthorsRelays, + }; + }); + } + return [ + { + filters: [this.filter], + relay: "", + strategy: RequestStrategy.DefaultRelays, + }, + ]; + } +} +exports.RequestFilterBuilder = RequestFilterBuilder; +_RequestFilterBuilder_filter = new WeakMap(), _RequestFilterBuilder_relayHints = new WeakMap(); +//# sourceMappingURL=RequestBuilder.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.js.map b/packages/system/dist/RequestBuilder.js.map new file mode 100644 index 00000000..74865223 --- /dev/null +++ b/packages/system/dist/RequestBuilder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestBuilder.js","sourceRoot":"","sources":["../src/RequestBuilder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,iCAA8C;AAC9C,uDAAgD;AAChD,+CAAsF;AACtF,mDAA+C;AAE/C;;GAEG;AACH,IAAY,eAgBX;AAhBD,WAAY,eAAe;IACzB;;;OAGG;IACH,uEAAiB,CAAA;IAEjB;;OAEG;IACH,uEAAiB,CAAA;IAEjB;;OAEG;IACH,mFAAuB,CAAA;AACzB,CAAC,EAhBW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAgB1B;AAoBD;;GAEG;AACH,MAAa,cAAc;IAKzB,YAAY,EAAU;;QAHtB,2CAAuC;QACvC,0CAAiC;QAG/B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,uBAAA,IAAI,4BAAa,EAAE,MAAA,CAAC;IACtB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,uBAAA,IAAI,gCAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,+BAAS,CAAC;IACvB,CAAC;IAED,UAAU;QACR,MAAM,GAAG,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACvC,uBAAA,IAAI,gCAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,WAAW,CAAC,GAA0B;QACpC,uBAAA,IAAI,2BAAY;YACd,GAAG,uBAAA,IAAI,+BAAS;YAChB,GAAG,GAAG;SACP,MAAA,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,OAAO,uBAAA,IAAI,gCAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,MAAkB;QACtB,MAAM,QAAQ,GAAG,uBAAA,IAAI,gCAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,uBAAA,IAAI,+DAAc,MAAlB,IAAI,EAAe,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,MAAkB,EAAE,OAAyB;QACrD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAA,6BAAW,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,OAAO,IAAA,mCAAqB,EAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACvD,OAAO;oBACL,QAAQ,EAAE,eAAe,CAAC,aAAa;oBACvC,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,KAAK,EAAE,CAAC,CAAC,KAAK;iBACf,CAAC;YACJ,CAAC,CAAC,CAAC;SACJ;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CA4BF;AAvFD,wCAuFC;mMArBe,QAAkC;IAC9C,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,QAAQ,EAAE;YACZ,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAClB;aAAM;YACL,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SACvB;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,IAAI,GAAG,EAAoC,CAAC,CAAC;IAEhD,MAAM,eAAe,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACxD,OAAO;YACL,OAAO,EAAE,IAAA,4BAAY,EAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChD,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;YACjB,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;SACH,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,eAAe,CAAC;AACzB,CAAC;AAGH;;GAEG;AACH,MAAa,oBAAoB;IAAjC;QACE,uCAAqB,EAAE,EAAC;QACxB,2CAAc,IAAI,GAAG,EAAuB,EAAC;IA0G/C,CAAC;IAxGC,IAAI,MAAM;QACR,OAAO,EAAE,GAAG,uBAAA,IAAI,oCAAQ,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,GAAG,CAAC,uBAAA,IAAI,wCAAY,CAAC,CAAC;IACnC,CAAC;IAED,GAAG,CAAC,GAAgB;QAClB,uBAAA,IAAI,oCAAQ,CAAC,GAAG,GAAG,IAAA,mBAAY,EAAC,uBAAA,IAAI,oCAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,EAAE,CAAC,EAAQ,EAAE,KAAc;QACzB,IAAI,KAAK,EAAE;YACT,uBAAA,IAAI,wCAAY,CAAC,GAAG,CAAC,EAAE,EAAE,IAAA,mBAAY,EAAC,uBAAA,IAAI,wCAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3E;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,OAAuB;QAC7B,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,uBAAA,IAAI,oCAAQ,CAAC,OAAO,GAAG,IAAA,mBAAY,EAAC,uBAAA,IAAI,oCAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAwB;QAC5B,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,uBAAA,IAAI,oCAAQ,CAAC,KAAK,GAAG,IAAA,mBAAY,EAAC,uBAAA,IAAI,oCAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAc;QAClB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,uBAAA,IAAI,oCAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAc;QAClB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,uBAAA,IAAI,oCAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAc;QAClB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,uBAAA,IAAI,oCAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,GAAgC,EAAE,KAAqB;QACzD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,uBAAA,IAAI,oCAAQ,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,OAAgB;QACrB,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,uBAAA,IAAI,oCAAQ,CAAC,MAAM,GAAG,OAAO,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAkB,EAAE,EAAU;QAClC,wDAAwD;QACxD,gEAAgE;QAChE,IAAI,uBAAA,IAAI,oCAAQ,CAAC,GAAG,IAAI,uBAAA,IAAI,wCAAY,CAAC,IAAI,GAAG,CAAC,EAAE;YACjD,MAAM,MAAM,GAAG,IAAA,aAAM,EAAC,CAAC,GAAG,uBAAA,IAAI,wCAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACpB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,GAAG,uBAAA,IAAI,oCAAQ;4BACf,GAAG,EAAE,CAAC,GAAG,uBAAA,IAAI,wCAAY,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;yBACtF;qBACF;oBACD,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,eAAe,CAAC,mBAAmB;iBAC9C,CAAC;YACJ,CAAC,CAAC,CAAC;SACJ;QAED,4EAA4E;QAC5E,IAAI,uBAAA,IAAI,oCAAQ,CAAC,OAAO,EAAE;YACxB,MAAM,KAAK,GAAG,IAAA,gCAAkB,EAAC,MAAM,EAAE,uBAAA,IAAI,oCAAQ,CAAC,CAAC;YACvD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBACnB,OAAO;oBACL,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;oBACnB,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,QAAQ,EAAE,eAAe,CAAC,aAAa;iBACxC,CAAC;YACJ,CAAC,CAAC,CAAC;SACJ;QAED,OAAO;YACL;gBACE,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;gBACtB,KAAK,EAAE,EAAE;gBACT,QAAQ,EAAE,eAAe,CAAC,aAAa;aACxC;SACF,CAAC;IACJ,CAAC;CACF;AA5GD,oDA4GC"} \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.d.ts b/packages/system/dist/RequestExpander.d.ts new file mode 100644 index 00000000..83b92600 --- /dev/null +++ b/packages/system/dist/RequestExpander.d.ts @@ -0,0 +1,20 @@ +import { u256, ReqFilter } from "./Nostr"; +export interface FlatReqFilter { + ids?: u256; + authors?: u256; + kinds?: number; + "#e"?: u256; + "#p"?: u256; + "#t"?: string; + "#d"?: string; + "#r"?: string; + search?: string; + since?: number; + until?: number; + limit?: number; +} +/** + * Expand a filter into its most fine grained form + */ +export declare function expandFilter(f: ReqFilter): Array; +//# sourceMappingURL=RequestExpander.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.d.ts.map b/packages/system/dist/RequestExpander.d.ts.map new file mode 100644 index 00000000..2f0419f8 --- /dev/null +++ b/packages/system/dist/RequestExpander.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestExpander.d.ts","sourceRoot":"","sources":["../src/RequestExpander.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,CA2B/D"} \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.js b/packages/system/dist/RequestExpander.js new file mode 100644 index 00000000..5cab53de --- /dev/null +++ b/packages/system/dist/RequestExpander.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.expandFilter = void 0; +/** + * Expand a filter into its most fine grained form + */ +function expandFilter(f) { + const ret = []; + const src = Object.entries(f); + const keys = src.filter(([, v]) => Array.isArray(v)).map(a => a[0]); + const props = src.filter(([, v]) => !Array.isArray(v)); + function generateCombinations(index, currentCombination) { + if (index === keys.length) { + ret.push(currentCombination); + return; + } + const key = keys[index]; + const values = f[key]; + for (let i = 0; i < values.length; i++) { + const value = values[i]; + const updatedCombination = { ...currentCombination, [key]: value }; + generateCombinations(index + 1, updatedCombination); + } + } + generateCombinations(0, { + ...Object.fromEntries(props), + }); + return ret; +} +exports.expandFilter = expandFilter; +//# sourceMappingURL=RequestExpander.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.js.map b/packages/system/dist/RequestExpander.js.map new file mode 100644 index 00000000..a347f38d --- /dev/null +++ b/packages/system/dist/RequestExpander.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestExpander.js","sourceRoot":"","sources":["../src/RequestExpander.ts"],"names":[],"mappings":";;;AAiBA;;GAEG;AACH,SAAgB,YAAY,CAAC,CAAY;IACvC,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,SAAS,oBAAoB,CAAC,KAAa,EAAE,kBAAiC;QAC5E,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE;YACzB,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC7B,OAAO;SACR;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,MAAM,GAAI,CAA4C,CAAC,GAAG,CAAC,CAAC;QAElE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,kBAAkB,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;YACnE,oBAAoB,CAAC,KAAK,GAAG,CAAC,EAAE,kBAAkB,CAAC,CAAC;SACrD;IACH,CAAC;IAED,oBAAoB,CAAC,CAAC,EAAE;QACtB,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;KAC7B,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC;AA3BD,oCA2BC"} \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.d.ts b/packages/system/dist/RequestMatcher.d.ts new file mode 100644 index 00000000..82948dca --- /dev/null +++ b/packages/system/dist/RequestMatcher.d.ts @@ -0,0 +1,3 @@ +import { NostrEvent, ReqFilter } from "./Nostr"; +export declare function eventMatchesFilter(ev: NostrEvent, filter: ReqFilter): boolean; +//# sourceMappingURL=RequestMatcher.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.d.ts.map b/packages/system/dist/RequestMatcher.d.ts.map new file mode 100644 index 00000000..e0dd95f6 --- /dev/null +++ b/packages/system/dist/RequestMatcher.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMatcher.d.ts","sourceRoot":"","sources":["../src/RequestMatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,WAiBnE"} \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.js b/packages/system/dist/RequestMatcher.js new file mode 100644 index 00000000..81583f43 --- /dev/null +++ b/packages/system/dist/RequestMatcher.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.eventMatchesFilter = void 0; +function eventMatchesFilter(ev, filter) { + if (!(filter.ids?.includes(ev.id) ?? false)) { + return false; + } + if (!(filter.authors?.includes(ev.pubkey) ?? false)) { + return false; + } + if (!(filter.kinds?.includes(ev.kind) ?? false)) { + return false; + } + if (filter.since && ev.created_at < filter.since) { + return false; + } + if (filter.until && ev.created_at > filter.until) { + return false; + } + return true; +} +exports.eventMatchesFilter = eventMatchesFilter; +//# sourceMappingURL=RequestMatcher.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.js.map b/packages/system/dist/RequestMatcher.js.map new file mode 100644 index 00000000..dcb35ecd --- /dev/null +++ b/packages/system/dist/RequestMatcher.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMatcher.js","sourceRoot":"","sources":["../src/RequestMatcher.ts"],"names":[],"mappings":";;;AAEA,SAAgB,kBAAkB,CAAC,EAAc,EAAE,MAAiB;IAClE,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE;QAC3C,OAAO,KAAK,CAAC;KACd;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE;QACnD,OAAO,KAAK,CAAC;KACd;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE;QAC/C,OAAO,KAAK,CAAC;KACd;IACD,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE;QAChD,OAAO,KAAK,CAAC;KACd;IACD,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE;QAChD,OAAO,KAAK,CAAC;KACd;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAjBD,gDAiBC"} \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.d.ts b/packages/system/dist/RequestMerger.d.ts new file mode 100644 index 00000000..47d16a22 --- /dev/null +++ b/packages/system/dist/RequestMerger.d.ts @@ -0,0 +1,24 @@ +import { ReqFilter } from "."; +import { FlatReqFilter } from "./RequestExpander"; +export declare function canMergeFilters(a: FlatReqFilter | ReqFilter, b: FlatReqFilter | ReqFilter): boolean; +export declare function mergeSimilar(filters: Array): Array; +/** + * Simply flatten all filters into one + * @param filters + * @returns + */ +export declare function simpleMerge(filters: Array): ReqFilter; +/** + * Check if a filter includes another filter, as in the bigger filter will include the same results as the samller filter + * @param bigger + * @param smaller + * @returns + */ +export declare function filterIncludes(bigger: ReqFilter, smaller: ReqFilter): boolean; +/** + * Merge expanded flat filters into combined concise filters + * @param all + * @returns + */ +export declare function flatMerge(all: Array): Array; +//# sourceMappingURL=RequestMerger.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.d.ts.map b/packages/system/dist/RequestMerger.d.ts.map new file mode 100644 index 00000000..bdc4e93b --- /dev/null +++ b/packages/system/dist/RequestMerger.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMerger.d.ts","sourceRoot":"","sources":["../src/RequestMerger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQlD,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,SAAS,EAAE,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAWnG;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAmBxE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,aAkBpD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,WAoBnE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAsDrE"} \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.js b/packages/system/dist/RequestMerger.js new file mode 100644 index 00000000..15dfd91c --- /dev/null +++ b/packages/system/dist/RequestMerger.js @@ -0,0 +1,150 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.flatMerge = exports.filterIncludes = exports.simpleMerge = exports.mergeSimilar = exports.canMergeFilters = void 0; +const Util_1 = require("./Util"); +/** + * Keys which can change the entire meaning of the filter outside the array types + */ +const DiscriminatorKeys = ["since", "until", "limit", "search"]; +function canMergeFilters(a, b) { + const aObj = a; + const bObj = b; + for (const key of DiscriminatorKeys) { + if (key in aObj || key in bObj) { + if (aObj[key] !== bObj[key]) { + return false; + } + } + } + return (0, Util_1.distance)(aObj, bObj) <= 1; +} +exports.canMergeFilters = canMergeFilters; +function mergeSimilar(filters) { + console.time("mergeSimilar"); + const ret = []; + const fCopy = [...filters]; + while (fCopy.length > 0) { + const current = fCopy.shift(); + const mergeSet = [current]; + for (let i = 0; i < fCopy.length; i++) { + const f = fCopy[i]; + if (mergeSet.every(v => canMergeFilters(v, f))) { + mergeSet.push(fCopy.splice(i, 1)[0]); + i--; + } + } + ret.push(simpleMerge(mergeSet)); + } + console.timeEnd("mergeSimilar"); + return ret; +} +exports.mergeSimilar = mergeSimilar; +/** + * Simply flatten all filters into one + * @param filters + * @returns + */ +function simpleMerge(filters) { + const result = {}; + filters.forEach(filter => { + Object.entries(filter).forEach(([key, value]) => { + if (Array.isArray(value)) { + if (result[key] === undefined) { + result[key] = [...value]; + } + else { + result[key] = [...new Set([...result[key], ...value])]; + } + } + else { + result[key] = value; + } + }); + }); + return result; +} +exports.simpleMerge = simpleMerge; +/** + * Check if a filter includes another filter, as in the bigger filter will include the same results as the samller filter + * @param bigger + * @param smaller + * @returns + */ +function filterIncludes(bigger, smaller) { + const outside = bigger; + for (const [k, v] of Object.entries(smaller)) { + if (outside[k] === undefined) { + return false; + } + if (Array.isArray(v) && v.some(a => !outside[k].includes(a))) { + return false; + } + if (typeof v === "number") { + if (k === "since" && outside[k] > v) { + return false; + } + if (k === "until" && outside[k] < v) { + return false; + } + // limit cannot be checked and is ignored + } + } + return true; +} +exports.filterIncludes = filterIncludes; +/** + * Merge expanded flat filters into combined concise filters + * @param all + * @returns + */ +function flatMerge(all) { + console.time("flatMerge"); + let ret = []; + // to compute filters which can be merged we need to calucate the distance change between each filter + // then we can merge filters which are exactly 1 change diff from each other + function mergeFiltersInSet(filters) { + const result = {}; + filters.forEach(f => { + const filter = f; + Object.entries(filter).forEach(([key, value]) => { + if (!DiscriminatorKeys.includes(key)) { + if (result[key] === undefined) { + result[key] = [value]; + } + else { + result[key] = [...new Set([...result[key], value])]; + } + } + else { + result[key] = value; + } + }); + }); + return result; + } + // reducer, kinda verbose + while (all.length > 0) { + const currentFilter = all.shift(); + const mergeSet = [currentFilter]; + for (let i = 0; i < all.length; i++) { + const f = all[i]; + if (mergeSet.every(a => canMergeFilters(a, f))) { + mergeSet.push(all.splice(i, 1)[0]); + i--; + } + } + ret.push(mergeFiltersInSet(mergeSet)); + } + while (true) { + const n = mergeSimilar([...ret]); + if (n.length === ret.length) { + break; + } + ret = n; + } + console.timeEnd("flatMerge"); + console.debug(ret); + return ret; +} +exports.flatMerge = flatMerge; +//# sourceMappingURL=RequestMerger.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.js.map b/packages/system/dist/RequestMerger.js.map new file mode 100644 index 00000000..80069d59 --- /dev/null +++ b/packages/system/dist/RequestMerger.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMerger.js","sourceRoot":"","sources":["../src/RequestMerger.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.d.ts b/packages/system/dist/RequestSplitter.d.ts new file mode 100644 index 00000000..85e70230 --- /dev/null +++ b/packages/system/dist/RequestSplitter.d.ts @@ -0,0 +1,7 @@ +import { ReqFilter } from "."; +export declare function diffFilters(prev: Array, next: Array): { + added: ReqFilter[]; + removed: ReqFilter[]; + changed: boolean; +}; +//# sourceMappingURL=RequestSplitter.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.d.ts.map b/packages/system/dist/RequestSplitter.d.ts.map new file mode 100644 index 00000000..ad0a50ef --- /dev/null +++ b/packages/system/dist/RequestSplitter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestSplitter.d.ts","sourceRoot":"","sources":["../src/RequestSplitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAK9B,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;;;;EAYzE"} \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.js b/packages/system/dist/RequestSplitter.js new file mode 100644 index 00000000..13488b3b --- /dev/null +++ b/packages/system/dist/RequestSplitter.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.diffFilters = void 0; +const Util_1 = require("./Util"); +const RequestExpander_1 = require("./RequestExpander"); +const RequestMerger_1 = require("./RequestMerger"); +function diffFilters(prev, next) { + const prevExpanded = prev.flatMap(RequestExpander_1.expandFilter); + const nextExpanded = next.flatMap(RequestExpander_1.expandFilter); + const added = (0, RequestMerger_1.flatMerge)(nextExpanded.filter(a => !prevExpanded.some(b => (0, Util_1.deepEqual)(a, b)))); + const removed = (0, RequestMerger_1.flatMerge)(prevExpanded.filter(a => !nextExpanded.some(b => (0, Util_1.deepEqual)(a, b)))); + return { + added, + removed, + changed: added.length > 0 || removed.length > 0, + }; +} +exports.diffFilters = diffFilters; +//# sourceMappingURL=RequestSplitter.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.js.map b/packages/system/dist/RequestSplitter.js.map new file mode 100644 index 00000000..71499c0e --- /dev/null +++ b/packages/system/dist/RequestSplitter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestSplitter.js","sourceRoot":"","sources":["../src/RequestSplitter.ts"],"names":[],"mappings":";;;AACA,iCAAmC;AACnC,uDAAiD;AACjD,mDAA4C;AAE5C,SAAgB,WAAW,CAAC,IAAsB,EAAE,IAAsB;IACxE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,8BAAY,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,8BAAY,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAG,IAAA,yBAAS,EAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,gBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAG,IAAA,yBAAS,EAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,gBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9F,OAAO;QACL,KAAK;QACL,OAAO;QACP,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;KAChD,CAAC;AACJ,CAAC;AAZD,kCAYC"} \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.d.ts b/packages/system/dist/SystemWorker.d.ts new file mode 100644 index 00000000..f9224e50 --- /dev/null +++ b/packages/system/dist/SystemWorker.d.ts @@ -0,0 +1,22 @@ +import { SystemSnapshot, SystemInterface } from "."; +import { AuthHandler, ConnectionStateSnapshot, RelaySettings } from "./Connection"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent } from "./Nostr"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { RequestBuilder } from "./RequestBuilder"; +export declare class SystemWorker extends ExternalStore implements SystemInterface { + #private; + constructor(); + HandleAuth?: AuthHandler; + get Sockets(): ConnectionStateSnapshot[]; + Query(type: new () => T, req: RequestBuilder | null): Query | undefined; + CancelQuery(sub: string): void; + GetQuery(sub: string): Query | undefined; + ConnectToRelay(address: string, options: RelaySettings): Promise; + DisconnectRelay(address: string): void; + BroadcastEvent(ev: NostrEvent): void; + WriteOnceToRelay(relay: string, ev: NostrEvent): Promise; + takeSnapshot(): SystemSnapshot; +} +//# sourceMappingURL=SystemWorker.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.d.ts.map b/packages/system/dist/SystemWorker.d.ts.map new file mode 100644 index 00000000..d6581294 --- /dev/null +++ b/packages/system/dist/SystemWorker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"SystemWorker.d.ts","sourceRoot":"","sources":["../src/SystemWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,YAAa,SAAQ,aAAa,CAAC,cAAc,CAAE,YAAW,eAAe;;;IAcxF,UAAU,CAAC,EAAE,WAAW,CAAC;IAEzB,IAAI,OAAO,IAAI,uBAAuB,EAAE,CAEvC;IAED,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS;IAI5F,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI9B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIxC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAItC,cAAc,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAIpC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,YAAY,IAAI,cAAc;CAO/B"} \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.js b/packages/system/dist/SystemWorker.js new file mode 100644 index 00000000..703bd8e1 --- /dev/null +++ b/packages/system/dist/SystemWorker.js @@ -0,0 +1,66 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _SystemWorker_instances, _SystemWorker_port, _SystemWorker_onMessage; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SystemWorker = void 0; +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +class SystemWorker extends ExternalStore_1.default { + constructor() { + super(); + _SystemWorker_instances.add(this); + _SystemWorker_port.set(this, void 0); + if ("SharedWorker" in window) { + const worker = new SharedWorker("/system.js"); + __classPrivateFieldSet(this, _SystemWorker_port, worker.port, "f"); + __classPrivateFieldGet(this, _SystemWorker_port, "f").onmessage = m => __classPrivateFieldGet(this, _SystemWorker_instances, "m", _SystemWorker_onMessage).call(this, m); + } + else { + throw new Error("SharedWorker is not supported"); + } + } + get Sockets() { + throw new Error("Method not implemented."); + } + Query(type, req) { + throw new Error("Method not implemented."); + } + CancelQuery(sub) { + throw new Error("Method not implemented."); + } + GetQuery(sub) { + throw new Error("Method not implemented."); + } + ConnectToRelay(address, options) { + throw new Error("Method not implemented."); + } + DisconnectRelay(address) { + throw new Error("Method not implemented."); + } + BroadcastEvent(ev) { + throw new Error("Method not implemented."); + } + WriteOnceToRelay(relay, ev) { + throw new Error("Method not implemented."); + } + takeSnapshot() { + throw new Error("Method not implemented."); + } +} +exports.SystemWorker = SystemWorker; +_SystemWorker_port = new WeakMap(), _SystemWorker_instances = new WeakSet(), _SystemWorker_onMessage = function _SystemWorker_onMessage(e) { + console.debug(e); +}; +//# sourceMappingURL=SystemWorker.js.map \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.js.map b/packages/system/dist/SystemWorker.js.map new file mode 100644 index 00000000..9b87a7f2 --- /dev/null +++ b/packages/system/dist/SystemWorker.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SystemWorker.js","sourceRoot":"","sources":["../src/SystemWorker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAEA,oEAA4C;AAM5C,MAAa,YAAa,SAAQ,uBAA6B;IAG7D;QACE,KAAK,EAAE,CAAC;;QAHV,qCAAmB;QAIjB,IAAI,cAAc,IAAI,MAAM,EAAE;YAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;YAC9C,uBAAA,IAAI,sBAAS,MAAM,CAAC,IAAI,MAAA,CAAC;YACzB,uBAAA,IAAI,0BAAM,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,uBAAA,IAAI,wDAAW,MAAf,IAAI,EAAY,CAAC,CAAC,CAAC;SAChD;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;SAClD;IACH,CAAC;IAID,IAAI,OAAO;QACT,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAsB,IAAiB,EAAE,GAA0B;QACtE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,WAAW,CAAC,GAAW;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,OAAe,EAAE,OAAsB;QACpD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,eAAe,CAAC,OAAe;QAC7B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,EAAc;QAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,gBAAgB,CAAC,KAAa,EAAE,EAAc;QAC5C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,YAAY;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CAKF;AAvDD,oCAuDC;wIAHY,CAAoB;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/Tag.d.ts b/packages/system/dist/Tag.d.ts new file mode 100644 index 00000000..d94498cb --- /dev/null +++ b/packages/system/dist/Tag.d.ts @@ -0,0 +1,18 @@ +import { HexKey, u256 } from "./Nostr"; +export default class Tag { + Original: string[]; + Key: string; + Event?: u256; + PubKey?: HexKey; + Relay?: string; + Marker?: string; + Hashtag?: string; + DTag?: string; + ATag?: string; + Index: number; + Invalid: boolean; + LNURL?: string; + constructor(tag: string[], index: number); + ToObject(): string[] | null; +} +//# sourceMappingURL=Tag.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Tag.d.ts.map b/packages/system/dist/Tag.d.ts.map new file mode 100644 index 00000000..a961ec79 --- /dev/null +++ b/packages/system/dist/Tag.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Tag.d.ts","sourceRoot":"","sources":["../src/Tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,CAAC,OAAO,OAAO,GAAG;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEH,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM;IAgDxC,QAAQ,IAAI,MAAM,EAAE,GAAG,IAAI;CAsB5B"} \ No newline at end of file diff --git a/packages/system/dist/Tag.js b/packages/system/dist/Tag.js new file mode 100644 index 00000000..3a0b281f --- /dev/null +++ b/packages/system/dist/Tag.js @@ -0,0 +1,75 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const Util_1 = require("./Util"); +class Tag { + constructor(tag, index) { + this.Original = tag; + this.Key = tag[0]; + this.Index = index; + this.Invalid = false; + switch (this.Key) { + case "e": { + // ["e", , , ] + this.Event = tag[1]; + this.Relay = tag.length > 2 ? tag[2] : undefined; + this.Marker = tag.length > 3 ? tag[3] : undefined; + if (!this.Event) { + this.Invalid = true; + } + break; + } + case "p": { + // ["p", ] + this.PubKey = tag[1]; + if (!this.PubKey) { + this.Invalid = true; + } + break; + } + case "d": { + this.DTag = tag[1]; + break; + } + case "a": { + this.ATag = tag[1]; + break; + } + case "t": { + this.Hashtag = tag[1]; + break; + } + case "delegation": { + this.PubKey = tag[1]; + break; + } + case "zap": { + this.LNURL = tag[1]; + break; + } + } + } + ToObject() { + switch (this.Key) { + case "e": { + let ret = ["e", this.Event, this.Relay, this.Marker]; + const trimEnd = ret.reverse().findIndex(a => a !== undefined); + ret = ret.reverse().slice(0, ret.length - trimEnd); + return ret; + } + case "p": { + return this.PubKey ? ["p", this.PubKey] : null; + } + case "t": { + return ["t", (0, Util_1.unwrap)(this.Hashtag)]; + } + case "d": { + return ["d", (0, Util_1.unwrap)(this.DTag)]; + } + default: { + return this.Original; + } + } + } +} +exports.default = Tag; +//# sourceMappingURL=Tag.js.map \ No newline at end of file diff --git a/packages/system/dist/Tag.js.map b/packages/system/dist/Tag.js.map new file mode 100644 index 00000000..1e6461c5 --- /dev/null +++ b/packages/system/dist/Tag.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Tag.js","sourceRoot":"","sources":["../src/Tag.ts"],"names":[],"mappings":";;AACA,iCAAgC;AAEhC,MAAqB,GAAG;IActB,YAAY,GAAa,EAAE,KAAa;QACtC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACpB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,QAAQ,IAAI,CAAC,GAAG,EAAE;YAChB,KAAK,GAAG,CAAC,CAAC;gBACR,2CAA2C;gBAC3C,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACpB,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACjD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAClD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;oBACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;iBACrB;gBACD,MAAM;aACP;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,kBAAkB;gBAClB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;oBAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;iBACrB;gBACD,MAAM;aACP;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnB,MAAM;aACP;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnB,MAAM;aACP;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM;aACP;YACD,KAAK,YAAY,CAAC,CAAC;gBACjB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACrB,MAAM;aACP;YACD,KAAK,KAAK,CAAC,CAAC;gBACV,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACpB,MAAM;aACP;SACF;IACH,CAAC;IAED,QAAQ;QACN,QAAQ,IAAI,CAAC,GAAG,EAAE;YAChB,KAAK,GAAG,CAAC,CAAC;gBACR,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBACrD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;gBAC9D,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;gBACnD,OAAiB,GAAG,CAAC;aACtB;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;aAChD;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,OAAO,CAAC,GAAG,EAAE,IAAA,aAAM,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;aACpC;YACD,KAAK,GAAG,CAAC,CAAC;gBACR,OAAO,CAAC,GAAG,EAAE,IAAA,aAAM,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;aACjC;YACD,OAAO,CAAC,CAAC;gBACP,OAAO,IAAI,CAAC,QAAQ,CAAC;aACtB;SACF;IACH,CAAC;CACF;AApFD,sBAoFC"} \ No newline at end of file diff --git a/packages/system/dist/Util.d.ts b/packages/system/dist/Util.d.ts new file mode 100644 index 00000000..b62acff4 --- /dev/null +++ b/packages/system/dist/Util.d.ts @@ -0,0 +1,23 @@ +import { NostrEvent, u256 } from "./Nostr"; +export declare function unwrap(v: T | undefined | null): T; +/** + * Convert hex to bech32 + */ +export declare function hexToBech32(hrp: string, hex?: string): string; +export declare function sanitizeRelayUrl(url: string): string | undefined; +export declare function unixNow(): number; +export declare function unixNowMs(): number; +export declare function deepEqual(x: any, y: any): boolean; +/** + * Compute the "distance" between two objects by comparing their difference in properties + * Missing/Added keys result in +10 distance + * This is not recursive + */ +export declare function distance(a: any, b: any): number; +export declare function dedupe(v: Array): T[]; +export declare function appendDedupe(a?: Array, b?: Array): T[]; +export declare function findTag(e: NostrEvent, tag: string): string | undefined; +export declare const sha256: (str: string | Uint8Array) => u256; +export declare function getPublicKey(privKey: string): string; +export declare function bech32ToHex(str: string): string; +//# sourceMappingURL=Util.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Util.d.ts.map b/packages/system/dist/Util.d.ts.map new file mode 100644 index 00000000..e7c9a5a5 --- /dev/null +++ b/packages/system/dist/Util.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Util.d.ts","sourceRoot":"","sources":["../src/Util.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE3C,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,CAKpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,UAYpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,sBAM3C;AAED,wBAAgB,OAAO,WAEtB;AAED,wBAAgB,SAAS,WAExB;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CA2B/C;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,OAEpC;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,OAEzD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,sBAKjD;AAED,eAAO,MAAM,MAAM,QAAS,MAAM,GAAG,UAAU,KAAG,IAEjD,CAAA;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,UAE3C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,UAQtC"} \ No newline at end of file diff --git a/packages/system/dist/Util.js b/packages/system/dist/Util.js new file mode 100644 index 00000000..92f0d069 --- /dev/null +++ b/packages/system/dist/Util.js @@ -0,0 +1,148 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bech32ToHex = exports.getPublicKey = exports.sha256 = exports.findTag = exports.appendDedupe = exports.dedupe = exports.distance = exports.deepEqual = exports.unixNowMs = exports.unixNow = exports.sanitizeRelayUrl = exports.hexToBech32 = exports.unwrap = void 0; +const utils = __importStar(require("@noble/curves/abstract/utils")); +const secp = __importStar(require("@noble/curves/secp256k1")); +const sha256_1 = require("@noble/hashes/sha256"); +const bech32_1 = require("bech32"); +function unwrap(v) { + if (v === undefined || v === null) { + throw new Error("missing value"); + } + return v; +} +exports.unwrap = unwrap; +/** + * Convert hex to bech32 + */ +function hexToBech32(hrp, hex) { + if (typeof hex !== "string" || hex.length === 0 || hex.length % 2 !== 0) { + return ""; + } + try { + const buf = utils.hexToBytes(hex); + return bech32_1.bech32.encode(hrp, bech32_1.bech32.toWords(buf)); + } + catch (e) { + console.warn("Invalid hex", hex, e); + return ""; + } +} +exports.hexToBech32 = hexToBech32; +function sanitizeRelayUrl(url) { + try { + return new URL(url).toString(); + } + catch { + // ignore + } +} +exports.sanitizeRelayUrl = sanitizeRelayUrl; +function unixNow() { + return Math.floor(unixNowMs() / 1000); +} +exports.unixNow = unixNow; +function unixNowMs() { + return new Date().getTime(); +} +exports.unixNowMs = unixNowMs; +function deepEqual(x, y) { + const ok = Object.keys, tx = typeof x, ty = typeof y; + return x && y && tx === "object" && tx === ty + ? ok(x).length === ok(y).length && ok(x).every(key => deepEqual(x[key], y[key])) + : x === y; +} +exports.deepEqual = deepEqual; +/** + * Compute the "distance" between two objects by comparing their difference in properties + * Missing/Added keys result in +10 distance + * This is not recursive + */ +function distance(a, b) { + const keys1 = Object.keys(a); + const keys2 = Object.keys(b); + const maxKeys = keys1.length > keys2.length ? keys1 : keys2; + let distance = 0; + for (const key of maxKeys) { + if (key in a && key in b) { + if (Array.isArray(a[key]) && Array.isArray(b[key])) { + const aa = a[key]; + const bb = b[key]; + if (aa.length === bb.length) { + if (aa.some(v => !bb.includes(v))) { + distance++; + } + } + else { + distance++; + } + } + else if (a[key] !== b[key]) { + distance++; + } + } + else { + distance += 10; + } + } + return distance; +} +exports.distance = distance; +function dedupe(v) { + return [...new Set(v)]; +} +exports.dedupe = dedupe; +function appendDedupe(a, b) { + return dedupe([...(a ?? []), ...(b ?? [])]); +} +exports.appendDedupe = appendDedupe; +function findTag(e, tag) { + const maybeTag = e.tags.find(evTag => { + return evTag[0] === tag; + }); + return maybeTag && maybeTag[1]; +} +exports.findTag = findTag; +const sha256 = (str) => { + return utils.bytesToHex((0, sha256_1.sha256)(str)); +}; +exports.sha256 = sha256; +function getPublicKey(privKey) { + return utils.bytesToHex(secp.schnorr.getPublicKey(privKey)); +} +exports.getPublicKey = getPublicKey; +function bech32ToHex(str) { + try { + const nKey = bech32_1.bech32.decode(str, 1000); + const buff = bech32_1.bech32.fromWords(nKey.words); + return utils.bytesToHex(Uint8Array.from(buff)); + } + catch (e) { + return str; + } +} +exports.bech32ToHex = bech32ToHex; +//# sourceMappingURL=Util.js.map \ No newline at end of file diff --git a/packages/system/dist/Util.js.map b/packages/system/dist/Util.js.map new file mode 100644 index 00000000..9846635c --- /dev/null +++ b/packages/system/dist/Util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Util.js","sourceRoot":"","sources":["../src/Util.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.d.ts b/packages/system/dist/WorkQueue.d.ts new file mode 100644 index 00000000..3b1df622 --- /dev/null +++ b/packages/system/dist/WorkQueue.d.ts @@ -0,0 +1,8 @@ +export interface WorkQueueItem { + next: () => Promise; + resolve(v: unknown): void; + reject(e: unknown): void; +} +export declare function processWorkQueue(queue?: Array, queueDelay?: number): Promise; +export declare const barrierQueue: (queue: Array, then: () => Promise) => Promise; +//# sourceMappingURL=WorkQueue.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.d.ts.map b/packages/system/dist/WorkQueue.d.ts.map new file mode 100644 index 00000000..2f91432e --- /dev/null +++ b/packages/system/dist/WorkQueue.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WorkQueue.d.ts","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,EAAE,UAAU,SAAM,iBAapF;AAED,eAAO,MAAM,YAAY,aAAoB,MAAM,aAAa,CAAC,uCAQhE,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.js b/packages/system/dist/WorkQueue.js new file mode 100644 index 00000000..b9d0b0d6 --- /dev/null +++ b/packages/system/dist/WorkQueue.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.barrierQueue = exports.processWorkQueue = void 0; +async function processWorkQueue(queue, queueDelay = 200) { + while (queue && queue.length > 0) { + const v = queue.shift(); + if (v) { + try { + const ret = await v.next(); + v.resolve(ret); + } + catch (e) { + v.reject(e); + } + } + } + setTimeout(() => processWorkQueue(queue, queueDelay), queueDelay); +} +exports.processWorkQueue = processWorkQueue; +const barrierQueue = async (queue, then) => { + return new Promise((resolve, reject) => { + queue.push({ + next: then, + resolve, + reject, + }); + }); +}; +exports.barrierQueue = barrierQueue; +//# sourceMappingURL=WorkQueue.js.map \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.js.map b/packages/system/dist/WorkQueue.js.map new file mode 100644 index 00000000..8f34b037 --- /dev/null +++ b/packages/system/dist/WorkQueue.js.map @@ -0,0 +1 @@ +{"version":3,"file":"WorkQueue.js","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";;;AAMO,KAAK,UAAU,gBAAgB,CAAC,KAA4B,EAAE,UAAU,GAAG,GAAG;IACnF,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QAChC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,EAAE;YACL,IAAI;gBACF,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;aAChB;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aACb;SACF;KACF;IACD,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;AACpE,CAAC;AAbD,4CAaC;AAEM,MAAM,YAAY,GAAG,KAAK,EAAK,KAA2B,EAAE,IAAsB,EAAc,EAAE;IACvG,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,IAAI;YACV,OAAO;YACP,MAAM;SACP,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AARW,QAAA,YAAY,gBAQvB"} \ No newline at end of file diff --git a/packages/system/dist/cache/index.d.ts b/packages/system/dist/cache/index.d.ts new file mode 100644 index 00000000..f8fc473f --- /dev/null +++ b/packages/system/dist/cache/index.d.ts @@ -0,0 +1,48 @@ +import { HexKey, NostrEvent, UserMetadata } from ".."; +export interface MetadataCache extends UserMetadata { + /** + * When the object was saved in cache + */ + loaded: number; + /** + * When the source metadata event was created + */ + created: number; + /** + * The pubkey of the owner of this metadata + */ + pubkey: HexKey; + /** + * The bech32 encoded pubkey + */ + npub: string; + /** + * Pubkey of zapper service + */ + zapService?: HexKey; + /** + * If the nip05 is valid for this user + */ + isNostrAddressValid: boolean; +} +export declare function mapEventToProfile(ev: NostrEvent): MetadataCache | undefined; +export interface CacheStore { + preload(): Promise; + getFromCache(key?: string): T | undefined; + get(key?: string): Promise; + bulkGet(keys: Array): Promise>; + set(obj: T): Promise; + bulkSet(obj: Array): Promise; + update(m: TCachedWithCreated): Promise<"new" | "updated" | "refresh" | "no_change">; + /** + * Loads a list of rows from disk cache + * @param keys List of ids to load + * @returns Keys that do not exist on disk cache + */ + buffer(keys: Array): Promise>; + clear(): Promise; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/cache/index.d.ts.map b/packages/system/dist/cache/index.d.ts.map new file mode 100644 index 00000000..65d321a7 --- /dev/null +++ b/packages/system/dist/cache/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAGtD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,6BAa/C;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAC1C,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,kBAAkB,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC,CAAA;IAEvJ;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"} \ No newline at end of file diff --git a/packages/system/dist/cache/index.js b/packages/system/dist/cache/index.js new file mode 100644 index 00000000..f21265bd --- /dev/null +++ b/packages/system/dist/cache/index.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mapEventToProfile = void 0; +const Util_1 = require("../Util"); +function mapEventToProfile(ev) { + try { + const data = JSON.parse(ev.content); + return { + ...data, + pubkey: ev.pubkey, + npub: (0, Util_1.hexToBech32)("npub", ev.pubkey), + created: ev.created_at, + loaded: (0, Util_1.unixNowMs)(), + }; + } + catch (e) { + console.error("Failed to parse JSON", ev, e); + } +} +exports.mapEventToProfile = mapEventToProfile; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/system/dist/cache/index.js.map b/packages/system/dist/cache/index.js.map new file mode 100644 index 00000000..6660f61b --- /dev/null +++ b/packages/system/dist/cache/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":";;;AACA,kCAAiD;AAkCjD,SAAgB,iBAAiB,CAAC,EAAc;IAC9C,IAAI;QACF,MAAM,IAAI,GAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAClD,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,IAAI,EAAE,IAAA,kBAAW,EAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC;YACpC,OAAO,EAAE,EAAE,CAAC,UAAU;YACtB,MAAM,EAAE,IAAA,gBAAS,GAAE;SACH,CAAC;KACpB;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;KAC9C;AACH,CAAC;AAbD,8CAaC"} \ No newline at end of file diff --git a/packages/system/dist/index.d.ts b/packages/system/dist/index.d.ts new file mode 100644 index 00000000..08c37550 --- /dev/null +++ b/packages/system/dist/index.d.ts @@ -0,0 +1,44 @@ +import { AuthHandler, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { RequestBuilder } from "./RequestBuilder"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { NostrEvent, ReqFilter } from "./Nostr"; +export * from "./NostrSystem"; +export { default as EventKind } from "./EventKind"; +export * from "./Nostr"; +export * from "./Links"; +export { default as Tag } from "./Tag"; +export * from "./Nips"; +export * from "./RelayInfo"; +export * from "./EventExt"; +export * from "./Connection"; +export * from "./NoteCollection"; +export * from "./RequestBuilder"; +export * from "./EventPublisher"; +export * from "./EventBuilder"; +export * from "./NostrLink"; +export * from "./cache"; +export * from "./ProfileCache"; +export interface SystemInterface { + /** + * Handler function for NIP-42 + */ + HandleAuth?: AuthHandler; + get Sockets(): Array; + GetQuery(id: string): Query | undefined; + Query(type: { + new (): T; + }, req: RequestBuilder | null): Query | undefined; + ConnectToRelay(address: string, options: RelaySettings): Promise; + DisconnectRelay(address: string): void; + BroadcastEvent(ev: NostrEvent): void; + WriteOnceToRelay(relay: string, ev: NostrEvent): Promise; +} +export interface SystemSnapshot { + queries: Array<{ + id: string; + filters: Array; + subFilters: Array; + }>; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/index.d.ts.map b/packages/system/dist/index.d.ts.map new file mode 100644 index 00000000..d9004955 --- /dev/null +++ b/packages/system/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAC;AACvC,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,IAAI,OAAO,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE;QAAE,QAAO,CAAC,CAAA;KAAE,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,CAAC;IAC9F,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1B,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;KAC9B,CAAC,CAAC;CACJ"} \ No newline at end of file diff --git a/packages/system/dist/index.js b/packages/system/dist/index.js new file mode 100644 index 00000000..9e8c83e3 --- /dev/null +++ b/packages/system/dist/index.js @@ -0,0 +1,39 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Tag = exports.EventKind = void 0; +__exportStar(require("./NostrSystem"), exports); +var EventKind_1 = require("./EventKind"); +Object.defineProperty(exports, "EventKind", { enumerable: true, get: function () { return __importDefault(EventKind_1).default; } }); +__exportStar(require("./Nostr"), exports); +__exportStar(require("./Links"), exports); +var Tag_1 = require("./Tag"); +Object.defineProperty(exports, "Tag", { enumerable: true, get: function () { return __importDefault(Tag_1).default; } }); +__exportStar(require("./Nips"), exports); +__exportStar(require("./RelayInfo"), exports); +__exportStar(require("./EventExt"), exports); +__exportStar(require("./Connection"), exports); +__exportStar(require("./NoteCollection"), exports); +__exportStar(require("./RequestBuilder"), exports); +__exportStar(require("./EventPublisher"), exports); +__exportStar(require("./EventBuilder"), exports); +__exportStar(require("./NostrLink"), exports); +__exportStar(require("./cache"), exports); +__exportStar(require("./ProfileCache"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/system/dist/index.js.map b/packages/system/dist/index.js.map new file mode 100644 index 00000000..a0e12b3a --- /dev/null +++ b/packages/system/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAMA,gDAA8B;AAC9B,yCAAmD;AAA1C,uHAAA,OAAO,OAAa;AAC7B,0CAAwB;AACxB,0CAAwB;AACxB,6BAAuC;AAA9B,2GAAA,OAAO,OAAO;AACvB,yCAAuB;AACvB,8CAA4B;AAC5B,6CAA2B;AAC3B,+CAA6B;AAC7B,mDAAiC;AACjC,mDAAiC;AACjC,mDAAiC;AACjC,iDAA+B;AAC/B,8CAA4B;AAC5B,0CAAwB;AACxB,iDAA+B"} \ No newline at end of file diff --git a/packages/system/jest.config.js b/packages/system/jest.config.js new file mode 100644 index 00000000..1ccd5800 --- /dev/null +++ b/packages/system/jest.config.js @@ -0,0 +1,9 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + bail: true, + preset: "ts-jest", + testEnvironment: "jsdom", + roots: ["src"], + moduleDirectories: ["src"], + setupFiles: ["./tests/setupTests.ts"], +}; diff --git a/packages/system/package.json b/packages/system/package.json new file mode 100644 index 00000000..ecdd59f6 --- /dev/null +++ b/packages/system/package.json @@ -0,0 +1,29 @@ +{ + "name": "@snort/system", + "version": "1.0.0", + "description": "Snort nostr system package", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "repository": "https://git.v0l.io/Kieran/snort", + "author": "Kieran", + "license": "GPLv3", + "scripts": { + "build": "rm -rf dist && tsc", + "test": "jest" + }, + "devDependencies": { + "@jest/globals": "^29.5.0", + "@types/jest": "^29.5.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "ts-jest": "^29.1.0", + "typescript": "^5.0.4" + }, + "dependencies": { + "@noble/curves": "^1.0.0", + "@protobufjs/base64": "^1.1.2", + "bech32": "^2.0.0", + "debug": "^4.3.4", + "uuid": "^9.0.0" + } +} diff --git a/packages/system/snort-system-1.0.0.tgz b/packages/system/snort-system-1.0.0.tgz new file mode 100644 index 00000000..3384474e Binary files /dev/null and b/packages/system/snort-system-1.0.0.tgz differ diff --git a/packages/app/src/System/Connection.ts b/packages/system/src/Connection.ts similarity index 99% rename from packages/app/src/System/Connection.ts rename to packages/system/src/Connection.ts index 109410e6..c4e11052 100644 --- a/packages/app/src/System/Connection.ts +++ b/packages/system/src/Connection.ts @@ -5,7 +5,7 @@ import { ConnectionStats } from "./ConnectionStats"; import { NostrEvent, ReqCommand, TaggedRawEvent, u256 } from "./Nostr"; import { RelayInfo } from "./RelayInfo"; import { unwrap } from "./Util"; -import ExternalStore from "ExternalStore"; +import ExternalStore from "./ExternalStore"; export type AuthHandler = (challenge: string, relay: string) => Promise; diff --git a/packages/app/src/System/ConnectionStats.ts b/packages/system/src/ConnectionStats.ts similarity index 100% rename from packages/app/src/System/ConnectionStats.ts rename to packages/system/src/ConnectionStats.ts diff --git a/packages/system/src/Const.ts b/packages/system/src/Const.ts new file mode 100644 index 00000000..f2e94a65 --- /dev/null +++ b/packages/system/src/Const.ts @@ -0,0 +1,16 @@ +/** + * Websocket re-connect timeout + */ +export const DefaultConnectTimeout = 2000; + +/** + * Hashtag regex + */ +// eslint-disable-next-line no-useless-escape +export const HashtagRegex = /(#[^\s!@#$%^&*()=+.\/,\[{\]};:'"?><]+)/g; + + +/** + * How long profile cache should be considered valid for + */ + export const ProfileCacheExpire = 1_000 * 60 * 60 * 6; \ No newline at end of file diff --git a/packages/app/src/System/EventBuilder.ts b/packages/system/src/EventBuilder.ts similarity index 91% rename from packages/app/src/System/EventBuilder.ts rename to packages/system/src/EventBuilder.ts index 73a285e1..d59bd647 100644 --- a/packages/app/src/System/EventBuilder.ts +++ b/packages/system/src/EventBuilder.ts @@ -1,7 +1,8 @@ -import { EventKind, HexKey, NostrPrefix, NostrEvent } from "System"; -import { HashtagRegex } from "Const"; -import { getPublicKey, parseNostrLink, unixNow } from "SnortUtils"; +import { EventKind, HexKey, NostrPrefix, NostrEvent } from "."; +import { HashtagRegex } from "./Const"; +import { getPublicKey, unixNow } from "./Util"; import { EventExt } from "./EventExt"; +import { parseNostrLink } from "./NostrLink"; export class EventBuilder { #kind?: EventKind; diff --git a/packages/app/src/System/EventExt.ts b/packages/system/src/EventExt.ts similarity index 92% rename from packages/app/src/System/EventExt.ts rename to packages/system/src/EventExt.ts index ebbf0f15..4df025ad 100644 --- a/packages/app/src/System/EventExt.ts +++ b/packages/system/src/EventExt.ts @@ -1,8 +1,8 @@ import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; -import { EventKind, HexKey, NostrEvent, Tag } from "System"; +import { EventKind, HexKey, NostrEvent, Tag } from "."; import base64 from "@protobufjs/base64"; -import { sha256, unixNow } from "SnortUtils"; +import { sha256, unixNow } from "./Util"; export interface Thread { root?: Tag; @@ -18,6 +18,7 @@ export abstract class EventExt { static getRootPubKey(e: NostrEvent): HexKey { const delegation = e.tags.find(a => a[0] === "delegation"); if (delegation?.[1]) { + // todo: verify sig return delegation[1]; } return e.pubkey; @@ -26,12 +27,12 @@ export abstract class EventExt { /** * Sign this message with a private key */ - static async sign(e: NostrEvent, key: HexKey) { + static sign(e: NostrEvent, key: HexKey) { e.id = this.createId(e); - const sig = await secp.schnorr.sign(e.id, key); + const sig = secp.schnorr.sign(e.id, key); e.sig = utils.bytesToHex(sig); - if (!(await secp.schnorr.verify(e.sig, e.id, e.pubkey))) { + if (!(secp.schnorr.verify(e.sig, e.id, e.pubkey))) { throw new Error("Signing failed"); } } @@ -40,9 +41,9 @@ export abstract class EventExt { * Check the signature of this message * @returns True if valid signature */ - static async verify(e: NostrEvent) { + static verify(e: NostrEvent) { const id = this.createId(e); - const result = await secp.schnorr.verify(e.sig, id, e.pubkey); + const result = secp.schnorr.verify(e.sig, id, e.pubkey); return result; } diff --git a/packages/app/src/System/EventKind.ts b/packages/system/src/EventKind.ts similarity index 100% rename from packages/app/src/System/EventKind.ts rename to packages/system/src/EventKind.ts diff --git a/packages/app/src/System/EventPublisher.ts b/packages/system/src/EventPublisher.ts similarity index 93% rename from packages/app/src/System/EventPublisher.ts rename to packages/system/src/EventPublisher.ts index 8aa29bad..b452bf48 100644 --- a/packages/app/src/System/EventPublisher.ts +++ b/packages/system/src/EventPublisher.ts @@ -11,13 +11,12 @@ import { TaggedRawEvent, u256, UserMetadata, -} from "System"; +} from "."; -import { DefaultRelays } from "Const"; -import { unwrap } from "SnortUtils"; +import { unwrap } from "./Util"; import { EventBuilder } from "./EventBuilder"; import { EventExt } from "./EventExt"; -import { barrierQueue, processWorkQueue, WorkQueueItem } from "WorkQueue"; +import { barrierQueue, processWorkQueue, WorkQueueItem } from "./WorkQueue"; const Nip7Queue: Array = []; processWorkQueue(Nip7Queue); @@ -118,17 +117,6 @@ export class EventPublisher { this.#system.BroadcastEvent(ev); } - /** - * Write event to DefaultRelays, this is important for profiles / relay lists to prevent bugs - * If a user removes all the DefaultRelays from their relay list and saves that relay list, - * When they open the site again we wont see that updated relay list and so it will appear to reset back to the previous state - */ - broadcastForBootstrap(ev: NostrEvent) { - for (const [k] of DefaultRelays) { - this.#system.WriteOnceToRelay(k, ev); - } - } - /** * Write event to all given relays. */ diff --git a/packages/system/src/ExternalStore.ts b/packages/system/src/ExternalStore.ts new file mode 100644 index 00000000..4b1dedea --- /dev/null +++ b/packages/system/src/ExternalStore.ts @@ -0,0 +1,41 @@ +type HookFn = (e?: TSnapshot) => void; + +interface HookFilter { + fn: HookFn; +} + +/** + * Simple React hookable store with manual change notifications + */ +export default abstract class ExternalStore { + #hooks: Array> = []; + #snapshot: Readonly = {} as Readonly; + #changed = true; + + hook(fn: HookFn) { + this.#hooks.push({ + fn, + }); + return () => { + const idx = this.#hooks.findIndex(a => a.fn === fn); + if (idx >= 0) { + this.#hooks.splice(idx, 1); + } + }; + } + + snapshot() { + if (this.#changed) { + this.#snapshot = this.takeSnapshot(); + this.#changed = false; + } + return this.#snapshot; + } + + protected notifyChange(sn?: TSnapshot) { + this.#changed = true; + this.#hooks.forEach(h => h.fn(sn)); + } + + abstract takeSnapshot(): TSnapshot; +} diff --git a/packages/app/src/System/GossipModel.ts b/packages/system/src/GossipModel.ts similarity index 96% rename from packages/app/src/System/GossipModel.ts rename to packages/system/src/GossipModel.ts index 5cdd2d41..07f8817e 100644 --- a/packages/app/src/System/GossipModel.ts +++ b/packages/system/src/GossipModel.ts @@ -1,5 +1,5 @@ -import { FullRelaySettings, ReqFilter } from "System"; -import { unwrap } from "SnortUtils"; +import { FullRelaySettings, ReqFilter } from "."; +import { unwrap } from "./Util"; import debug from "debug"; const PickNRelays = 2; diff --git a/packages/app/src/System/Links.ts b/packages/system/src/Links.ts similarity index 100% rename from packages/app/src/System/Links.ts rename to packages/system/src/Links.ts diff --git a/packages/app/src/System/Nips.ts b/packages/system/src/Nips.ts similarity index 100% rename from packages/app/src/System/Nips.ts rename to packages/system/src/Nips.ts diff --git a/packages/app/src/System/Nostr.ts b/packages/system/src/Nostr.ts similarity index 100% rename from packages/app/src/System/Nostr.ts rename to packages/system/src/Nostr.ts diff --git a/packages/system/src/NostrLink.ts b/packages/system/src/NostrLink.ts new file mode 100644 index 00000000..cb663b3b --- /dev/null +++ b/packages/system/src/NostrLink.ts @@ -0,0 +1,110 @@ +import { bech32ToHex, hexToBech32 } from "./Util"; +import { NostrPrefix, decodeTLV, TLVEntryType } from "."; + +export interface NostrLink { + type: NostrPrefix; + id: string; + kind?: number; + author?: string; + relays?: Array; + encode(): string; + } + + export function validateNostrLink(link: string): boolean { + try { + const parsedLink = parseNostrLink(link); + if (!parsedLink) { + return false; + } + if (parsedLink.type === NostrPrefix.PublicKey || parsedLink.type === NostrPrefix.Note) { + return parsedLink.id.length === 64; + } + + return true; + } catch { + return false; + } + } + + export function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined { + try { + return parseNostrLink(link, prefixHint); + } catch { + return undefined; + } + } + + export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink { + const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; + + const isPrefix = (prefix: NostrPrefix) => { + return entity.startsWith(prefix); + }; + + if (isPrefix(NostrPrefix.PublicKey)) { + const id = bech32ToHex(entity); + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.PublicKey, + id: id, + encode: () => hexToBech32(NostrPrefix.PublicKey, id), + }; + } else if (isPrefix(NostrPrefix.Note)) { + const id = bech32ToHex(entity); + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Note, + id: id, + encode: () => hexToBech32(NostrPrefix.Note, id), + }; + } else if (isPrefix(NostrPrefix.Profile) || isPrefix(NostrPrefix.Event) || isPrefix(NostrPrefix.Address)) { + const decoded = decodeTLV(entity); + + const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string; + const relays = decoded.filter(a => a.type === TLVEntryType.Relay).map(a => a.value as string); + const author = decoded.find(a => a.type === TLVEntryType.Author)?.value as string; + const kind = decoded.find(a => a.type === TLVEntryType.Kind)?.value as number; + + const encode = () => { + return entity; // return original + }; + if (isPrefix(NostrPrefix.Profile)) { + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Profile, + id, + relays, + kind, + author, + encode, + }; + } else if (isPrefix(NostrPrefix.Event)) { + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Event, + id, + relays, + kind, + author, + encode, + }; + } else if (isPrefix(NostrPrefix.Address)) { + return { + type: NostrPrefix.Address, + id, + relays, + kind, + author, + encode, + }; + } + } else if (prefixHint) { + return { + type: prefixHint, + id: link, + encode: () => hexToBech32(prefixHint, link), + }; + } + throw new Error("Invalid nostr link"); + } + \ No newline at end of file diff --git a/packages/app/src/System/NostrSystem.ts b/packages/system/src/NostrSystem.ts similarity index 95% rename from packages/app/src/System/NostrSystem.ts rename to packages/system/src/NostrSystem.ts index a34a641f..c20b96a8 100644 --- a/packages/app/src/System/NostrSystem.ts +++ b/packages/system/src/NostrSystem.ts @@ -1,15 +1,14 @@ import debug from "debug"; -import { v4 as uuid } from "uuid"; -import ExternalStore from "ExternalStore"; -import { NostrEvent, ReqFilter, TaggedRawEvent } from "./Nostr"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent, TaggedRawEvent } from "./Nostr"; import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; -import { Query, QueryBase } from "./Query"; +import { Query } from "./Query"; import { RelayCache } from "./GossipModel"; import { NoteStore } from "./NoteCollection"; import { BuiltRawReqFilter, RequestBuilder } from "./RequestBuilder"; -import { unwrap, sanitizeRelayUrl, unixNowMs } from "./Util"; -import { SystemInterface, SystemSnapshot } from "System"; +import { unwrap, sanitizeRelayUrl } from "./Util"; +import { SystemInterface, SystemSnapshot } from "."; /** * Manages nostr content retrieval system diff --git a/packages/app/src/System/NoteCollection.ts b/packages/system/src/NoteCollection.ts similarity index 98% rename from packages/app/src/System/NoteCollection.ts rename to packages/system/src/NoteCollection.ts index 85974f14..f33e41f7 100644 --- a/packages/app/src/System/NoteCollection.ts +++ b/packages/system/src/NoteCollection.ts @@ -1,5 +1,5 @@ -import { TaggedRawEvent, u256 } from "System"; -import { appendDedupe, findTag } from "SnortUtils"; +import { TaggedRawEvent, u256 } from "."; +import { appendDedupe, findTag } from "./Util"; export interface StoreSnapshot { data: TSnapshot | undefined; diff --git a/packages/app/src/System/ProfileCache.ts b/packages/system/src/ProfileCache.ts similarity index 83% rename from packages/app/src/System/ProfileCache.ts rename to packages/system/src/ProfileCache.ts index fe49f371..7a21c6c9 100644 --- a/packages/app/src/System/ProfileCache.ts +++ b/packages/system/src/ProfileCache.ts @@ -1,13 +1,12 @@ -import { EventKind, HexKey, SystemInterface, TaggedRawEvent } from "System"; -import { ProfileCacheExpire } from "Const"; -import { mapEventToProfile, MetadataCache } from "Cache"; -import { UserCache } from "Cache/UserCache"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; -import { unixNowMs } from "SnortUtils"; +import { EventKind, HexKey, SystemInterface, TaggedRawEvent, PubkeyReplaceableNoteStore, RequestBuilder } from "."; +import { ProfileCacheExpire } from "./Const"; +import { CacheStore, mapEventToProfile, MetadataCache } from "./cache"; +import { unixNowMs } from "./Util"; import debug from "debug"; export class ProfileLoaderService { #system: SystemInterface; + #cache: CacheStore; /** * List of pubkeys to fetch metadata for @@ -16,8 +15,9 @@ export class ProfileLoaderService { readonly #log = debug("ProfileCache"); - constructor(system: SystemInterface) { + constructor(system: SystemInterface, cache: CacheStore) { this.#system = system; + this.#cache = cache; this.#FetchMetadata(); } @@ -31,7 +31,7 @@ export class ProfileLoaderService { bufferNow.push(p); } } - UserCache.buffer(bufferNow); + this.#cache.buffer(bufferNow); } /** @@ -48,17 +48,17 @@ export class ProfileLoaderService { async onProfileEvent(e: Readonly) { const profile = mapEventToProfile(e); if (profile) { - await UserCache.update(profile); + await this.#cache.update(profile); } } async #FetchMetadata() { - const missingFromCache = await UserCache.buffer([...this.WantsMetadata]); + const missingFromCache = await this.#cache.buffer([...this.WantsMetadata]); const expire = unixNowMs() - ProfileCacheExpire; const expired = [...this.WantsMetadata] .filter(a => !missingFromCache.includes(a)) - .filter(a => (UserCache.getFromCache(a)?.loaded ?? 0) < expire); + .filter(a => (this.#cache.getFromCache(a)?.loaded ?? 0) < expire); const missing = new Set([...missingFromCache, ...expired]); if (missing.size > 0) { this.#log("Wants profiles: %d missing, %d expired", missingFromCache.length, expired.length); @@ -104,7 +104,7 @@ export class ProfileLoaderService { if (couldNotFetch.length > 0) { this.#log("No profiles: %o", couldNotFetch); const empty = couldNotFetch.map(a => - UserCache.update({ + this.#cache.update({ pubkey: a, loaded: unixNowMs() - ProfileCacheExpire + 5_000, // expire in 5s created: 69, diff --git a/packages/app/src/System/Query.ts b/packages/system/src/Query.ts similarity index 96% rename from packages/app/src/System/Query.ts rename to packages/system/src/Query.ts index 581d37f1..4ec3a4df 100644 --- a/packages/app/src/System/Query.ts +++ b/packages/system/src/Query.ts @@ -1,10 +1,9 @@ import { v4 as uuid } from "uuid"; import debug from "debug"; -import { Connection, ReqFilter, Nips, TaggedRawEvent } from "System"; -import { unixNowMs, unwrap } from "SnortUtils"; +import { Connection, ReqFilter, Nips, TaggedRawEvent } from "."; +import { unixNowMs, unwrap } from "./Util"; import { NoteStore } from "./NoteCollection"; -import { flatMerge, mergeSimilar, simpleMerge } from "./RequestMerger"; -import { eventMatchesFilter } from "./RequestMatcher"; +import { flatMerge } from "./RequestMerger"; import { BuiltRawReqFilter } from "./RequestBuilder"; import { expandFilter } from "./RequestExpander"; diff --git a/packages/app/src/System/RelayInfo.ts b/packages/system/src/RelayInfo.ts similarity index 100% rename from packages/app/src/System/RelayInfo.ts rename to packages/system/src/RelayInfo.ts diff --git a/packages/app/src/System/RequestBuilder.ts b/packages/system/src/RequestBuilder.ts similarity index 98% rename from packages/app/src/System/RequestBuilder.ts rename to packages/system/src/RequestBuilder.ts index dfbbb8b5..a565da9a 100644 --- a/packages/app/src/System/RequestBuilder.ts +++ b/packages/system/src/RequestBuilder.ts @@ -1,5 +1,5 @@ -import { ReqFilter, u256, HexKey, EventKind } from "System"; -import { appendDedupe, dedupe } from "SnortUtils"; +import { ReqFilter, u256, HexKey, EventKind } from "."; +import { appendDedupe, dedupe } from "./Util"; import { diffFilters } from "./RequestSplitter"; import { RelayCache, splitAllByWriteRelays, splitByWriteRelays } from "./GossipModel"; import { mergeSimilar } from "./RequestMerger"; diff --git a/packages/app/src/System/RequestExpander.ts b/packages/system/src/RequestExpander.ts similarity index 100% rename from packages/app/src/System/RequestExpander.ts rename to packages/system/src/RequestExpander.ts diff --git a/packages/app/src/System/RequestMatcher.ts b/packages/system/src/RequestMatcher.ts similarity index 100% rename from packages/app/src/System/RequestMatcher.ts rename to packages/system/src/RequestMatcher.ts diff --git a/packages/app/src/System/RequestMerger.ts b/packages/system/src/RequestMerger.ts similarity index 99% rename from packages/app/src/System/RequestMerger.ts rename to packages/system/src/RequestMerger.ts index bd588c25..db0403fe 100644 --- a/packages/app/src/System/RequestMerger.ts +++ b/packages/system/src/RequestMerger.ts @@ -1,4 +1,4 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "."; import { FlatReqFilter } from "./RequestExpander"; import { distance } from "./Util"; diff --git a/packages/app/src/System/RequestSplitter.ts b/packages/system/src/RequestSplitter.ts similarity index 94% rename from packages/app/src/System/RequestSplitter.ts rename to packages/system/src/RequestSplitter.ts index e1a3d653..2231d8b5 100644 --- a/packages/app/src/System/RequestSplitter.ts +++ b/packages/system/src/RequestSplitter.ts @@ -1,4 +1,4 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "."; import { deepEqual } from "./Util"; import { expandFilter } from "./RequestExpander"; import { flatMerge } from "./RequestMerger"; diff --git a/packages/app/src/System/SystemWorker.ts b/packages/system/src/SystemWorker.ts similarity index 80% rename from packages/app/src/System/SystemWorker.ts rename to packages/system/src/SystemWorker.ts index fb80e02a..ab9dfaf3 100644 --- a/packages/app/src/System/SystemWorker.ts +++ b/packages/system/src/SystemWorker.ts @@ -1,15 +1,10 @@ -import ExternalStore from "ExternalStore"; -import { - NoteStore, - Query, - NostrEvent, - RelaySettings, - RequestBuilder, - SystemSnapshot, - SystemInterface, - ConnectionStateSnapshot, - AuthHandler, -} from "System"; +import { SystemSnapshot, SystemInterface } from "."; +import { AuthHandler, ConnectionStateSnapshot, RelaySettings } from "./Connection"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent } from "./Nostr"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { RequestBuilder } from "./RequestBuilder"; export class SystemWorker extends ExternalStore implements SystemInterface { #port: MessagePort; diff --git a/packages/app/src/System/Tag.ts b/packages/system/src/Tag.ts similarity index 100% rename from packages/app/src/System/Tag.ts rename to packages/system/src/Tag.ts diff --git a/packages/app/src/System/Util.ts b/packages/system/src/Util.ts similarity index 68% rename from packages/app/src/System/Util.ts rename to packages/system/src/Util.ts index c5698739..a0053736 100644 --- a/packages/app/src/System/Util.ts +++ b/packages/system/src/Util.ts @@ -1,5 +1,8 @@ import * as utils from "@noble/curves/abstract/utils"; +import * as secp from "@noble/curves/secp256k1"; +import { sha256 as sha2 } from "@noble/hashes/sha256"; import { bech32 } from "bech32"; +import { NostrEvent, u256 } from "./Nostr"; export function unwrap(v: T | undefined | null): T { if (v === undefined || v === null) { @@ -84,3 +87,36 @@ export function distance(a: any, b: any): number { return distance; } + +export function dedupe(v: Array) { + return [...new Set(v)]; +} + +export function appendDedupe(a?: Array, b?: Array) { + return dedupe([...(a ?? []), ...(b ?? [])]); +} + +export function findTag(e: NostrEvent, tag: string) { + const maybeTag = e.tags.find(evTag => { + return evTag[0] === tag; + }); + return maybeTag && maybeTag[1]; +} + +export const sha256 = (str: string | Uint8Array): u256 => { + return utils.bytesToHex(sha2(str)); +} + +export function getPublicKey(privKey: string) { + return utils.bytesToHex(secp.schnorr.getPublicKey(privKey)); +} + +export function bech32ToHex(str: string) { + try { + const nKey = bech32.decode(str, 1_000); + const buff = bech32.fromWords(nKey.words); + return utils.bytesToHex(Uint8Array.from(buff)); + } catch (e) { + return str; + } +} diff --git a/packages/system/src/WorkQueue.ts b/packages/system/src/WorkQueue.ts new file mode 100644 index 00000000..37df22e0 --- /dev/null +++ b/packages/system/src/WorkQueue.ts @@ -0,0 +1,30 @@ +export interface WorkQueueItem { + next: () => Promise; + resolve(v: unknown): void; + reject(e: unknown): void; +} + +export async function processWorkQueue(queue?: Array, queueDelay = 200) { + while (queue && queue.length > 0) { + const v = queue.shift(); + if (v) { + try { + const ret = await v.next(); + v.resolve(ret); + } catch (e) { + v.reject(e); + } + } + } + setTimeout(() => processWorkQueue(queue, queueDelay), queueDelay); +} + +export const barrierQueue = async (queue: Array, then: () => Promise): Promise => { + return new Promise((resolve, reject) => { + queue.push({ + next: then, + resolve, + reject, + }); + }); +}; diff --git a/packages/system/src/cache/index.ts b/packages/system/src/cache/index.ts new file mode 100644 index 00000000..431318a0 --- /dev/null +++ b/packages/system/src/cache/index.ts @@ -0,0 +1,68 @@ +import { HexKey, NostrEvent, UserMetadata } from ".."; +import { hexToBech32, unixNowMs } from "../Util"; + +export interface MetadataCache extends UserMetadata { + /** + * When the object was saved in cache + */ + loaded: number; + + /** + * When the source metadata event was created + */ + created: number; + + /** + * The pubkey of the owner of this metadata + */ + pubkey: HexKey; + + /** + * The bech32 encoded pubkey + */ + npub: string; + + /** + * Pubkey of zapper service + */ + zapService?: HexKey; + + /** + * If the nip05 is valid for this user + */ + isNostrAddressValid: boolean; +} + +export function mapEventToProfile(ev: NostrEvent) { + try { + const data: UserMetadata = JSON.parse(ev.content); + return { + ...data, + pubkey: ev.pubkey, + npub: hexToBech32("npub", ev.pubkey), + created: ev.created_at, + loaded: unixNowMs(), + } as MetadataCache; + } catch (e) { + console.error("Failed to parse JSON", ev, e); + } +} + +export interface CacheStore { + preload(): Promise; + getFromCache(key?: string): T | undefined; + get(key?: string): Promise; + bulkGet(keys: Array): Promise>; + set(obj: T): Promise; + bulkSet(obj: Array): Promise; + update(m: TCachedWithCreated): Promise<"new" | "updated" | "refresh" | "no_change"> + + /** + * Loads a list of rows from disk cache + * @param keys List of ids to load + * @returns Keys that do not exist on disk cache + */ + buffer(keys: Array): Promise>; + + clear(): Promise; +} diff --git a/packages/app/src/System/index.ts b/packages/system/src/index.ts similarity index 58% rename from packages/app/src/System/index.ts rename to packages/system/src/index.ts index fd40e81e..4f11456c 100644 --- a/packages/app/src/System/index.ts +++ b/packages/system/src/index.ts @@ -1,13 +1,6 @@ -import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { AuthHandler, RelaySettings, ConnectionStateSnapshot } from "./Connection"; import { RequestBuilder } from "./RequestBuilder"; -import { EventBuilder } from "./EventBuilder"; -import { - FlatNoteStore, - NoteStore, - PubkeyReplaceableNoteStore, - ParameterizedReplaceableNoteStore, - ReplaceableNoteStore, -} from "./NoteCollection"; +import { NoteStore } from "./NoteCollection"; import { Query } from "./Query"; import { NostrEvent, ReqFilter } from "./Nostr"; @@ -18,6 +11,15 @@ export * from "./Links"; export { default as Tag } from "./Tag"; export * from "./Nips"; export * from "./RelayInfo"; +export * from "./EventExt"; +export * from "./Connection"; +export * from "./NoteCollection"; +export * from "./RequestBuilder"; +export * from "./EventPublisher"; +export * from "./EventBuilder"; +export * from "./NostrLink"; +export * from "./cache"; +export * from "./ProfileCache"; export interface SystemInterface { /** @@ -26,7 +28,7 @@ export interface SystemInterface { HandleAuth?: AuthHandler; get Sockets(): Array; GetQuery(id: string): Query | undefined; - Query(type: { new (): T }, req: RequestBuilder | null): Query | undefined; + Query(type: { new(): T }, req: RequestBuilder | null): Query | undefined; ConnectToRelay(address: string, options: RelaySettings): Promise; DisconnectRelay(address: string): void; BroadcastEvent(ev: NostrEvent): void; @@ -39,19 +41,4 @@ export interface SystemSnapshot { filters: Array; subFilters: Array; }>; -} - -export { - NoteStore, - RequestBuilder, - FlatNoteStore, - PubkeyReplaceableNoteStore, - ParameterizedReplaceableNoteStore, - ReplaceableNoteStore, - Query, - EventBuilder, - AuthHandler, - Connection, - RelaySettings, - ConnectionStateSnapshot, -}; +} \ No newline at end of file diff --git a/packages/app/src/System/NoteCollection.test.ts b/packages/system/tests/NoteCollection.test.ts similarity index 93% rename from packages/app/src/System/NoteCollection.test.ts rename to packages/system/tests/NoteCollection.test.ts index 00eb6086..613bc63d 100644 --- a/packages/app/src/System/NoteCollection.test.ts +++ b/packages/system/tests/NoteCollection.test.ts @@ -1,6 +1,6 @@ -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "../src/Nostr"; import { describe, expect } from "@jest/globals"; -import { FlatNoteStore, ReplaceableNoteStore } from "./NoteCollection"; +import { FlatNoteStore, ReplaceableNoteStore } from "../src/NoteCollection"; describe("NoteStore", () => { describe("flat", () => { diff --git a/packages/app/src/System/Query.test.ts b/packages/system/tests/Query.test.ts similarity index 92% rename from packages/app/src/System/Query.test.ts rename to packages/system/tests/Query.test.ts index ad80a1a4..3c026319 100644 --- a/packages/app/src/System/Query.test.ts +++ b/packages/system/tests/Query.test.ts @@ -1,9 +1,9 @@ -import { Connection } from "System"; +import { Connection } from "../src"; import { describe, expect } from "@jest/globals"; -import { Query, QueryBase } from "./Query"; +import { Query } from "../src/Query"; import { getRandomValues } from "crypto"; -import { FlatNoteStore } from "./NoteCollection"; -import { RequestStrategy } from "./RequestBuilder"; +import { FlatNoteStore } from "../src/NoteCollection"; +import { RequestStrategy } from "../src/RequestBuilder"; window.crypto = {} as any; window.crypto.getRandomValues = getRandomValues as any; diff --git a/packages/app/src/System/RequestBuilder.test.ts b/packages/system/tests/RequestBuilder.test.ts similarity index 97% rename from packages/app/src/System/RequestBuilder.test.ts rename to packages/system/tests/RequestBuilder.test.ts index e2546cda..b0ec6f99 100644 --- a/packages/app/src/System/RequestBuilder.test.ts +++ b/packages/system/tests/RequestBuilder.test.ts @@ -1,5 +1,5 @@ -import { RelayCache } from "./GossipModel"; -import { RequestBuilder, RequestStrategy } from "./RequestBuilder"; +import { RelayCache } from "../src/GossipModel"; +import { RequestBuilder, RequestStrategy } from "../src/RequestBuilder"; import { describe, expect } from "@jest/globals"; const DummyCache = { diff --git a/packages/app/src/System/RequestExpander.test.ts b/packages/system/tests/RequestExpander.test.ts similarity index 96% rename from packages/app/src/System/RequestExpander.test.ts rename to packages/system/tests/RequestExpander.test.ts index 0ccb58d1..d87faf7b 100644 --- a/packages/app/src/System/RequestExpander.test.ts +++ b/packages/system/tests/RequestExpander.test.ts @@ -1,4 +1,4 @@ -import { expandFilter } from "./RequestExpander"; +import { expandFilter } from "../src/RequestExpander"; describe("RequestExpander", () => { test("expand filter", () => { diff --git a/packages/app/src/System/RequestMatcher.test.ts b/packages/system/tests/RequestMatcher.test.ts similarity index 88% rename from packages/app/src/System/RequestMatcher.test.ts rename to packages/system/tests/RequestMatcher.test.ts index 49754ff5..0b7a4b39 100644 --- a/packages/app/src/System/RequestMatcher.test.ts +++ b/packages/system/tests/RequestMatcher.test.ts @@ -1,4 +1,4 @@ -import { eventMatchesFilter } from "./RequestMatcher"; +import { eventMatchesFilter } from "../src/RequestMatcher"; describe("RequestMatcher", () => { it("should match simple filter", () => { diff --git a/packages/app/src/System/RequestMerger.test.ts b/packages/system/tests/RequestMerger.test.ts similarity index 93% rename from packages/app/src/System/RequestMerger.test.ts rename to packages/system/tests/RequestMerger.test.ts index b2020d36..d9ac51cf 100644 --- a/packages/app/src/System/RequestMerger.test.ts +++ b/packages/system/tests/RequestMerger.test.ts @@ -1,7 +1,7 @@ -import { ReqFilter } from "System"; -import { filterIncludes, flatMerge, mergeSimilar, simpleMerge } from "./RequestMerger"; -import { FlatReqFilter, expandFilter } from "./RequestExpander"; -import { distance } from "./Util"; +import { ReqFilter } from "../src"; +import { filterIncludes, flatMerge, mergeSimilar, simpleMerge } from "../src/RequestMerger"; +import { FlatReqFilter, expandFilter } from "../src/RequestExpander"; +import { distance } from "../src/Util"; describe("RequestMerger", () => { it("should simple merge authors", () => { diff --git a/packages/app/src/System/RequestSplitter.test.ts b/packages/system/tests/RequestSplitter.test.ts similarity index 96% rename from packages/app/src/System/RequestSplitter.test.ts rename to packages/system/tests/RequestSplitter.test.ts index e6caa5a7..7e639e34 100644 --- a/packages/app/src/System/RequestSplitter.test.ts +++ b/packages/system/tests/RequestSplitter.test.ts @@ -1,6 +1,6 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "../src"; import { describe, expect } from "@jest/globals"; -import { diffFilters } from "./RequestSplitter"; +import { diffFilters } from "../src/RequestSplitter"; describe("RequestSplitter", () => { test("single filter add value", () => { diff --git a/packages/system/tests/Util.test.ts b/packages/system/tests/Util.test.ts new file mode 100644 index 00000000..baebd7a2 --- /dev/null +++ b/packages/system/tests/Util.test.ts @@ -0,0 +1,117 @@ +import { distance } from "../src/Util"; + +describe("distance", () => { + it("should have 0 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "a", + }; + expect(distance(a, b)).toEqual(0); + }); + it("should have 1 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "b", + }; + expect(distance(a, b)).toEqual(1); + }); + it("should have 10 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "a", + kinds: 1, + }; + expect(distance(a, b)).toEqual(10); + }); + it("should have 11 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "b", + kinds: 1, + }; + expect(distance(a, b)).toEqual(11); + }); + it("should have 1 distance, arrays", () => { + const a = { + since: 1, + until: 100, + kinds: [1], + authors: ["kieran", "snort", "c", "d", "e"], + }; + const b = { + since: 1, + until: 100, + kinds: [6969], + authors: ["kieran", "snort", "c", "d", "e"], + }; + expect(distance(a, b)).toEqual(1); + }); + it("should have 1 distance, array change extra", () => { + const a = { + since: 1, + until: 100, + kinds: [1], + authors: ["f", "kieran", "snort", "c", "d"], + }; + const b = { + since: 1, + until: 100, + kinds: [1], + authors: ["kieran", "snort", "c", "d", "e"], + }; + expect(distance(a, b)).toEqual(1); + }); +}); + + +describe("tryParseNostrLink", () => { + it("is a valid nostr link", () => { + expect(parseNostrLink("nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ + id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", + type: NostrPrefix.PublicKey, + }); + expect(parseNostrLink("web+nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ + id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", + type: NostrPrefix.PublicKey, + }); + expect(parseNostrLink("nostr:note15449edq4qa5wzgqvh8td0q0dp6hwtes4pknsrm7eygeenhlj99xsq94wu9")).toMatchObject({ + id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", + type: NostrPrefix.Note, + }); + expect( + parseNostrLink( + "nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p" + ) + ).toMatchObject({ + id: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", + type: NostrPrefix.Profile, + relays: ["wss://r.x.com", "wss://djbas.sadkb.com"], + }); + expect(parseNostrLink("nostr:nevent1qqs226juks2sw68pyqxtn4khs8ksath9uc2smfcpalvjyvuemlezjngrd87dq")).toMatchObject({ + id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", + type: NostrPrefix.Event, + }); + expect( + parseNostrLink( + "nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu" + ) + ).toMatchObject({ + id: "ipsum", + type: NostrPrefix.Address, + relays: ["wss://relay.nostr.org"], + author: "a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919", + kind: 30023, + }); + }); + test.each(["nostr:npub", "web+nostr:npub", "nostr:nevent1xxx"])("should return false for invalid nostr links", lb => { + expect(tryParseNostrLink(lb)).toBeUndefined(); + }); +}); diff --git a/packages/system/tests/setupTests.ts b/packages/system/tests/setupTests.ts new file mode 100644 index 00000000..4930f245 --- /dev/null +++ b/packages/system/tests/setupTests.ts @@ -0,0 +1,3 @@ +import { TextEncoder, TextDecoder } from "util"; + +Object.assign(global, { TextDecoder, TextEncoder }); diff --git a/packages/system/tsconfig.json b/packages/system/tsconfig.json new file mode 100644 index 00000000..dca184be --- /dev/null +++ b/packages/system/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "target": "ES2020", + "moduleResolution": "node", + "esModuleInterop": true, + "noImplicitOverride": true, + "module": "CommonJS", + "strict": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "skipLibCheck": true + }, + "include": ["src"], + "files": ["src/index.ts"] +} diff --git a/packages/app/src/System/worker.ts b/packages/system/worker.ts similarity index 88% rename from packages/app/src/System/worker.ts rename to packages/system/worker.ts index 4f47dad8..88315188 100644 --- a/packages/app/src/System/worker.ts +++ b/packages/system/worker.ts @@ -1,5 +1,5 @@ /// -import { UsersRelaysCache } from "Cache/UserRelayCache"; +import { UsersRelaysCache } from "../Cache/UserRelayCache"; import { NostrSystem } from "."; declare const self: SharedWorkerGlobalScope;