system-pkg #577

Merged
Kieran merged 2 commits from system-pkg into gossip-model 2023-06-08 22:45:19 +00:00
141 changed files with 842 additions and 620 deletions

3
.gitignore vendored
View File

@ -2,3 +2,6 @@ node_modules/
.idea
.yarn
yarn.lock
dist/
*.tgz
*.log

View File

@ -23,3 +23,5 @@ yarn-debug.log*
yarn-error.log*
.idea
dist/

View File

@ -1,4 +1,4 @@
import { NostrEvent } from "System";
import { NostrEvent } from "@snort/system";
import { db } from "Db";
import FeedCache from "./FeedCache";

View File

@ -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";

View File

@ -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<string>) {
const preloads = [
UserCache.preload(follows),

View File

@ -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

View File

@ -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;

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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 }) {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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;

View File

@ -1,4 +1,4 @@
import { TaggedRawEvent } from "System";
import { TaggedRawEvent } from "@snort/system";
import { useState } from "react";
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";

View File

@ -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 {

View File

@ -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 {

View File

@ -1,4 +1,4 @@
import { NostrEvent } from "System";
import { NostrEvent } from "@snort/system";
import { dedupe } from "SnortUtils";
import FollowListBase from "./FollowListBase";

View File

@ -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";

View File

@ -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";

View File

@ -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 }) => {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -1,4 +1,4 @@
import { NostrEvent } from "System";
import { NostrEvent } from "@snort/system";
export interface TrendingUser {
pubkey: string;

View File

@ -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 = {

View File

@ -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";

View File

@ -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(() => {

View File

@ -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() {

View File

@ -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) {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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) {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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) {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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() {

View File

@ -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";

View File

@ -1,4 +1,4 @@
import { HexKey, NostrEvent } from "System";
import { HexKey, NostrEvent } from "@snort/system";
import { EmailRegex } from "Const";
import { bech32ToText, unwrap } from "SnortUtils";

View File

@ -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<string, RelaySettings>, createdAt: number) {

View File

@ -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";

View File

@ -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";

View File

@ -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 {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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() {

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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);

View File

@ -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;

View File

@ -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();
});
});

View File

@ -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<string>;
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();

View File

@ -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;

View File

@ -1,5 +1,5 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { NostrEvent } from "System";
import { NostrEvent } from "@snort/system";
interface ReBroadcastStore {
show: boolean;

View File

@ -1,4 +0,0 @@
/**
* Websocket re-connect timeout
*/
export const DefaultConnectTimeout = 2000;

View File

@ -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);
});
});

View File

@ -1,86 +0,0 @@
import * as utils from "@noble/curves/abstract/utils";
import { bech32 } from "bech32";
export function unwrap<T>(v: T | undefined | null): T {
if (v === undefined || v === null) {
throw new Error("missing value");
}
return v;
}
/**
* Convert hex to bech32
*/
export function hexToBech32(hrp: string, hex?: string) {
if (typeof hex !== "string" || hex.length === 0 || hex.length % 2 !== 0) {
return "";
}
try {
const buf = utils.hexToBytes(hex);
return bech32.encode(hrp, bech32.toWords(buf));
} catch (e) {
console.warn("Invalid hex", hex, e);
return "";
}
}
export function sanitizeRelayUrl(url: string) {
try {
return new URL(url).toString();
} catch {
// ignore
}
}
export function unixNow() {
return Math.floor(unixNowMs() / 1000);
}
export function unixNowMs() {
return new Date().getTime();
}
export function deepEqual(x: any, y: any): boolean {
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;
}
/**
* Compute the "distance" between two objects by comparing their difference in properties
* Missing/Added keys result in +10 distance
* This is not recursive
*/
export function distance(a: any, b: any): number {
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] as Array<string | number>;
const bb = b[key] as Array<string | number>;
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;
}

View File

@ -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 {

View File

@ -1,4 +1,4 @@
import { MetadataCache } from "Cache";
import { MetadataCache } from "@snort/system";
export interface UITask {
id: string;

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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=";

View File

@ -0,0 +1,6 @@
tests/
src/
*.tgz
jest.config.js
worker.ts
yarn*

View File

@ -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"],
};

Some files were not shown because too many files have changed in this diff Show More