move to pkg
This commit is contained in:
parent
2b80109e3b
commit
81ccb95d82
2
packages/app/.gitignore
vendored
2
packages/app/.gitignore
vendored
@ -23,3 +23,5 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
|
dist/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NostrEvent } from "System";
|
import { NostrEvent } from "@snort/system";
|
||||||
import { db } from "Db";
|
import { db } from "Db";
|
||||||
import FeedCache from "./FeedCache";
|
import FeedCache from "./FeedCache";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import FeedCache from "Cache/FeedCache";
|
import FeedCache from "Cache/FeedCache";
|
||||||
import { db } from "Db";
|
import { db } from "Db";
|
||||||
import { MetadataCache } from "Cache";
|
import { MetadataCache } from "@snort/system";
|
||||||
import { LNURL } from "LNURL";
|
import { LNURL } from "LNURL";
|
||||||
import { fetchNip05Pubkey } from "Nip05/Verifier";
|
import { fetchNip05Pubkey } from "Nip05/Verifier";
|
||||||
|
|
||||||
|
@ -1,57 +1,8 @@
|
|||||||
import { HexKey, NostrEvent, UserMetadata } from "System";
|
|
||||||
import { hexToBech32, unixNowMs } from "SnortUtils";
|
|
||||||
import { DmCache } from "./DMCache";
|
import { DmCache } from "./DMCache";
|
||||||
import { InteractionCache } from "./EventInteractionCache";
|
import { InteractionCache } from "./EventInteractionCache";
|
||||||
import { UserCache } from "./UserCache";
|
import { UserCache } from "./UserCache";
|
||||||
import { UserRelays } from "./UserRelayCache";
|
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>) {
|
export async function preload(follows?: Array<string>) {
|
||||||
const preloads = [
|
const preloads = [
|
||||||
UserCache.preload(follows),
|
UserCache.preload(follows),
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { UserRelays } from "Cache/UserRelayCache";
|
import { RelaySettings } from "@snort/system";
|
||||||
import { NostrSystem, RelaySettings } from "System";
|
|
||||||
import { ProfileLoaderService } from "System/ProfileCache";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add-on api for snort features
|
* Add-on api for snort features
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import Dexie, { Table } from "dexie";
|
import Dexie, { Table } from "dexie";
|
||||||
import { FullRelaySettings, HexKey, NostrEvent, u256 } from "System";
|
import { FullRelaySettings, HexKey, NostrEvent, u256, MetadataCache } from "@snort/system";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
|
|
||||||
export const NAME = "snortDB";
|
export const NAME = "snortDB";
|
||||||
export const VERSION = 8;
|
export const VERSION = 8;
|
||||||
|
@ -2,7 +2,7 @@ import "./Avatar.css";
|
|||||||
import Nostrich from "nostrich.webp";
|
import Nostrich from "nostrich.webp";
|
||||||
|
|
||||||
import { CSSProperties, useEffect, useState } from "react";
|
import { CSSProperties, useEffect, useState } from "react";
|
||||||
import type { UserMetadata } from "System";
|
import type { UserMetadata } from "@snort/system";
|
||||||
|
|
||||||
import useImgProxy from "Hooks/useImgProxy";
|
import useImgProxy from "Hooks/useImgProxy";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import "./BadgeList.css";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import { TaggedRawEvent } from "System";
|
import { TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
import { ProxyImg } from "Element/ProxyImg";
|
import { ProxyImg } from "Element/ProxyImg";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useState, useMemo, ChangeEvent } from "react";
|
import { useState, useMemo, ChangeEvent } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey, TaggedRawEvent } from "System";
|
import { HexKey, TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
import Note from "Element/Note";
|
import Note from "Element/Note";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
@ -2,7 +2,7 @@ import "./DM.css";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { useInView } from "react-intersection-observer";
|
import { useInView } from "react-intersection-observer";
|
||||||
import { TaggedRawEvent } from "System";
|
import { TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import NoteTime from "Element/NoteTime";
|
import NoteTime from "Element/NoteTime";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "./DmWindow.css";
|
import "./DmWindow.css";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { TaggedRawEvent } from "System";
|
import { TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
import ProfileImage from "Element/ProfileImage";
|
import ProfileImage from "Element/ProfileImage";
|
||||||
import DM from "Element/DM";
|
import DM from "Element/DM";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "./FollowButton.css";
|
import "./FollowButton.css";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import { parseId } from "SnortUtils";
|
import { parseId } from "SnortUtils";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import ProfilePreview from "Element/ProfilePreview";
|
import ProfilePreview from "Element/ProfilePreview";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { profileLink } from "SnortUtils";
|
import { profileLink } from "SnortUtils";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import MuteButton from "Element/MuteButton";
|
import MuteButton from "Element/MuteButton";
|
||||||
import ProfilePreview from "Element/ProfilePreview";
|
import ProfilePreview from "Element/ProfilePreview";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "./Nip05.css";
|
import "./Nip05.css";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useMemo, useState, ChangeEvent } from "react";
|
import { useEffect, useMemo, useState, ChangeEvent } from "react";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { UserMetadata } from "System";
|
import { UserMetadata, mapEventToProfile } from "@snort/system";
|
||||||
|
|
||||||
import { unwrap } from "SnortUtils";
|
import { unwrap } from "SnortUtils";
|
||||||
import { formatShort } from "Number";
|
import { formatShort } from "Number";
|
||||||
@ -22,7 +22,7 @@ import useEventPublisher from "Feed/EventPublisher";
|
|||||||
import { debounce } from "SnortUtils";
|
import { debounce } from "SnortUtils";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import SnortServiceProvider from "Nip05/SnortServiceProvider";
|
import SnortServiceProvider from "Nip05/SnortServiceProvider";
|
||||||
import { mapEventToProfile, UserCache } from "Cache";
|
import { UserCache } from "Cache";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
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 useEventFeed from "Feed/EventFeed";
|
||||||
import PageSpinner from "Element/PageSpinner";
|
import PageSpinner from "Element/PageSpinner";
|
||||||
import Reveal from "Element/Reveal";
|
import Reveal from "Element/Reveal";
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { NostrPrefix } from "System";
|
import { NostrPrefix, parseNostrLink } from "@snort/system";
|
||||||
|
|
||||||
import Mention from "Element/Mention";
|
import Mention from "Element/Mention";
|
||||||
import { parseNostrLink } from "SnortUtils";
|
|
||||||
import NoteQuote from "Element/NoteQuote";
|
import NoteQuote from "Element/NoteQuote";
|
||||||
|
|
||||||
export default function NostrLink({ link, depth }: { link: string; depth?: number }) {
|
export default function NostrLink({ link, depth }: { link: string; depth?: number }) {
|
||||||
|
@ -3,7 +3,7 @@ import React, { useMemo, useState, useLayoutEffect, ReactNode } from "react";
|
|||||||
import { useNavigate, Link } from "react-router-dom";
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
import { useInView } from "react-intersection-observer";
|
import { useInView } from "react-intersection-observer";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
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 useEventPublisher from "Feed/EventPublisher";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
@ -26,7 +26,6 @@ import Reveal from "Element/Reveal";
|
|||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
import { UserCache } from "Cache/UserCache";
|
import { UserCache } from "Cache/UserCache";
|
||||||
import Poll from "Element/Poll";
|
import Poll from "Element/Poll";
|
||||||
import { EventExt } from "System/EventExt";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { setBookmarked, setPinned } from "Login";
|
import { setBookmarked, setPinned } from "Login";
|
||||||
import { NostrFileElement } from "Element/NostrFileHeader";
|
import { NostrFileElement } from "Element/NostrFileHeader";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import "./NoteCreator.css";
|
import "./NoteCreator.css";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
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 Icon from "Icons/Icon";
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
@ -31,7 +31,6 @@ import { LNURL } from "LNURL";
|
|||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
import { ClipboardEventHandler, useState } from "react";
|
import { ClipboardEventHandler, useState } from "react";
|
||||||
import Spinner from "Icons/Spinner";
|
import Spinner from "Icons/Spinner";
|
||||||
import { EventBuilder } from "System";
|
|
||||||
import { Menu, MenuItem } from "@szhsin/react-menu";
|
import { Menu, MenuItem } from "@szhsin/react-menu";
|
||||||
import { LoginStore } from "Login";
|
import { LoginStore } from "Login";
|
||||||
import { getCurrentSubscription } from "Subscription";
|
import { getCurrentSubscription } from "Subscription";
|
||||||
|
@ -3,7 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
|
|||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { Menu, MenuItem } from "@szhsin/react-menu";
|
import { Menu, MenuItem } from "@szhsin/react-menu";
|
||||||
import { useLongPress } from "use-long-press";
|
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 Icon from "Icons/Icon";
|
||||||
import Spinner from "Icons/Spinner";
|
import Spinner from "Icons/Spinner";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import useEventFeed from "Feed/EventFeed";
|
import useEventFeed from "Feed/EventFeed";
|
||||||
import { NostrLink } from "SnortUtils";
|
import { NostrLink } from "@snort/system";
|
||||||
import Note from "Element/Note";
|
import Note from "Element/Note";
|
||||||
import PageSpinner from "Element/PageSpinner";
|
import PageSpinner from "Element/PageSpinner";
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import "./NoteReaction.css";
|
import "./NoteReaction.css";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useMemo } from "react";
|
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 Note from "Element/Note";
|
||||||
import ProfileImage from "Element/ProfileImage";
|
import ProfileImage from "Element/ProfileImage";
|
||||||
import { eventLink, hexToBech32 } from "SnortUtils";
|
import { eventLink, hexToBech32 } from "SnortUtils";
|
||||||
import NoteTime from "Element/NoteTime";
|
import NoteTime from "Element/NoteTime";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
import { EventExt } from "System/EventExt";
|
|
||||||
|
|
||||||
export interface NoteReactionProps {
|
export interface NoteReactionProps {
|
||||||
data: TaggedRawEvent;
|
data: TaggedRawEvent;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { TaggedRawEvent } from "System";
|
import { TaggedRawEvent } from "@snort/system";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import "./ProfileImage.css";
|
import "./ProfileImage.css";
|
||||||
|
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { HexKey, NostrPrefix } from "System";
|
import { HexKey, NostrPrefix, MetadataCache } from "@snort/system";
|
||||||
|
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { hexToBech32, profileLink } from "SnortUtils";
|
import { hexToBech32, profileLink } from "SnortUtils";
|
||||||
import Avatar from "Element/Avatar";
|
import Avatar from "Element/Avatar";
|
||||||
import Nip05 from "Element/Nip05";
|
import Nip05 from "Element/Nip05";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
export interface ProfileImageProps {
|
export interface ProfileImageProps {
|
||||||
|
@ -4,7 +4,7 @@ import { ReactNode } from "react";
|
|||||||
import ProfileImage from "Element/ProfileImage";
|
import ProfileImage from "Element/ProfileImage";
|
||||||
import FollowButton from "Element/FollowButton";
|
import FollowButton from "Element/FollowButton";
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import { useInView } from "react-intersection-observer";
|
import { useInView } from "react-intersection-observer";
|
||||||
|
|
||||||
export interface ProfilePreviewProps {
|
export interface ProfilePreviewProps {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NostrEvent } from "System";
|
import { NostrEvent } from "@snort/system";
|
||||||
import { dedupe } from "SnortUtils";
|
import { dedupe } from "SnortUtils";
|
||||||
import FollowListBase from "./FollowListBase";
|
import FollowListBase from "./FollowListBase";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import "./Reactions.css";
|
|||||||
|
|
||||||
import { useState, useMemo, useEffect } from "react";
|
import { useState, useMemo, useEffect } from "react";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { TaggedRawEvent } from "System";
|
import { TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
import { formatShort } from "Number";
|
import { formatShort } from "Number";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
|
@ -2,7 +2,7 @@ import "./Relay.css";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { RelaySettings } from "System";
|
import { RelaySettings } from "@snort/system";
|
||||||
|
|
||||||
import useRelayState from "Feed/RelayState";
|
import useRelayState from "Feed/RelayState";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
@ -2,7 +2,7 @@ import "./RelaysMetadata.css";
|
|||||||
import Nostrich from "nostrich.webp";
|
import Nostrich from "nostrich.webp";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { FullRelaySettings } from "System";
|
import { FullRelaySettings } from "@snort/system";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
|
|
||||||
const RelayFavicon = ({ url }: { url: string }) => {
|
const RelayFavicon = ({ url }: { url: string }) => {
|
||||||
|
@ -2,7 +2,7 @@ import "./SendSats.css";
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import { HexKey, NostrEvent } from "System";
|
import { HexKey, NostrEvent, EventPublisher } from "@snort/system";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
import { formatShort } from "Number";
|
import { formatShort } from "Number";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
@ -16,7 +16,6 @@ import { chunks, debounce } from "SnortUtils";
|
|||||||
import { useWallet } from "Wallet";
|
import { useWallet } from "Wallet";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { generateRandomKey } from "Login";
|
import { generateRandomKey } from "Login";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
|
||||||
import { ZapPoolController } from "ZapPoolController";
|
import { ZapPoolController } from "ZapPoolController";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
@ -5,7 +5,7 @@ import useRelayState from "Feed/RelayState";
|
|||||||
import Tabs, { Tab } from "Element/Tabs";
|
import Tabs, { Tab } from "Element/Tabs";
|
||||||
import { unwrap } from "SnortUtils";
|
import { unwrap } from "SnortUtils";
|
||||||
import useSystemState from "Hooks/useSystemState";
|
import useSystemState from "Hooks/useSystemState";
|
||||||
import { ReqFilter } from "System";
|
import { ReqFilter } from "@snort/system";
|
||||||
import { useCopy } from "useCopy";
|
import { useCopy } from "useCopy";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { HexKey, NostrPrefix } from "System";
|
import { HexKey, NostrPrefix } from "@snort/system";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import FollowListBase from "Element/FollowListBase";
|
import FollowListBase from "Element/FollowListBase";
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import "./Text.css";
|
import "./Text.css";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Link, useLocation } from "react-router-dom";
|
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 { 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 Invoice from "Element/Invoice";
|
||||||
import Hashtag from "Element/Hashtag";
|
import Hashtag from "Element/Hashtag";
|
||||||
import Mention from "Element/Mention";
|
import Mention from "Element/Mention";
|
||||||
|
@ -4,12 +4,11 @@ import "./Textarea.css";
|
|||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
|
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
|
||||||
import TextareaAutosize from "react-textarea-autosize";
|
import TextareaAutosize from "react-textarea-autosize";
|
||||||
import { NostrPrefix } from "System";
|
import { NostrPrefix, MetadataCache } from "@snort/system";
|
||||||
|
|
||||||
import Avatar from "Element/Avatar";
|
import Avatar from "Element/Avatar";
|
||||||
import Nip05 from "Element/Nip05";
|
import Nip05 from "Element/Nip05";
|
||||||
import { hexToBech32 } from "SnortUtils";
|
import { hexToBech32 } from "SnortUtils";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
import { UserCache } from "Cache/UserCache";
|
import { UserCache } from "Cache/UserCache";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
@ -2,10 +2,17 @@ import "./Thread.css";
|
|||||||
import { useMemo, useState, ReactNode } from "react";
|
import { useMemo, useState, ReactNode } from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { useNavigate, useLocation, Link, useParams } from "react-router-dom";
|
import { useNavigate, useLocation, Link, useParams } from "react-router-dom";
|
||||||
import { TaggedRawEvent, u256, EventKind, NostrPrefix } from "System";
|
import {
|
||||||
import { EventExt, Thread as ThreadInfo } from "System/EventExt";
|
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 BackButton from "Element/BackButton";
|
||||||
import Note from "Element/Note";
|
import Note from "Element/Note";
|
||||||
import NoteGhost from "Element/NoteGhost";
|
import NoteGhost from "Element/NoteGhost";
|
||||||
|
@ -2,7 +2,7 @@ import "./Timeline.css";
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useInView } from "react-intersection-observer";
|
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 Icon from "Icons/Icon";
|
||||||
import { dedupeByPubkey, findTag, tagFilterOfTextRepost } from "SnortUtils";
|
import { dedupeByPubkey, findTag, tagFilterOfTextRepost } from "SnortUtils";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { NostrEvent, TaggedRawEvent } from "System";
|
import { NostrEvent, TaggedRawEvent } from "@snort/system";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import PageSpinner from "Element/PageSpinner";
|
import PageSpinner from "Element/PageSpinner";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import FollowListBase from "Element/FollowListBase";
|
import FollowListBase from "Element/FollowListBase";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MouseEvent } from "react";
|
import { MouseEvent } from "react";
|
||||||
import { useNavigate, Link } from "react-router-dom";
|
import { useNavigate, Link } from "react-router-dom";
|
||||||
|
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { profileLink } from "SnortUtils";
|
import { profileLink } from "SnortUtils";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { encodeTLV, NostrPrefix, NostrEvent } from "System";
|
import { encodeTLV, NostrPrefix, NostrEvent } from "@snort/system";
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
import Spinner from "Icons/Spinner";
|
import Spinner from "Icons/Spinner";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import "./Zap.css";
|
import "./Zap.css";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
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 { decodeInvoice, InvoiceDetails, sha256, unwrap } from "SnortUtils";
|
||||||
import { formatShort } from "Number";
|
import { formatShort } from "Number";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "./ZapButton.css";
|
import "./ZapButton.css";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import SendSats from "Element/SendSats";
|
import SendSats from "Element/SendSats";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "./ZapstrEmbed.css";
|
import "./ZapstrEmbed.css";
|
||||||
import { Link } from "react-router-dom";
|
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 { ProxyImg } from "Element/ProxyImg";
|
||||||
import ProfileImage from "Element/ProfileImage";
|
import ProfileImage from "Element/ProfileImage";
|
||||||
|
2
packages/app/src/External/NostrBand.ts
vendored
2
packages/app/src/External/NostrBand.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import { NostrEvent } from "System";
|
import { NostrEvent } from "@snort/system";
|
||||||
|
|
||||||
export interface TrendingUser {
|
export interface TrendingUser {
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { useMemo } from "react";
|
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 { unwrap, findTag, chunks } from "SnortUtils";
|
||||||
import { RequestBuilder } from "System";
|
|
||||||
import { FlatNoteStore, ReplaceableNoteStore } from "System/NoteCollection";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
|
|
||||||
type BadgeAwards = {
|
type BadgeAwards = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HexKey, Lists } from "System";
|
import { HexKey, Lists } from "@snort/system";
|
||||||
|
|
||||||
import useNotelistSubscription from "Hooks/useNotelistSubscription";
|
import useNotelistSubscription from "Hooks/useNotelistSubscription";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { NostrPrefix } from "System";
|
import { NostrPrefix, RequestBuilder, ReplaceableNoteStore, NostrLink } from "@snort/system";
|
||||||
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import { RequestBuilder, ReplaceableNoteStore } from "System";
|
import { unwrap } from "SnortUtils";
|
||||||
import { NostrLink, unwrap } from "SnortUtils";
|
|
||||||
|
|
||||||
export default function useEventFeed(link: NostrLink) {
|
export default function useEventFeed(link: NostrLink) {
|
||||||
const sub = useMemo(() => {
|
const sub = useMemo(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
import { EventPublisher } from "@snort/system";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
|
||||||
export default function useEventPublisher() {
|
export default function useEventPublisher() {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
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";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
|
|
||||||
export default function useFollowersFeed(pubkey?: HexKey) {
|
export default function useFollowersFeed(pubkey?: HexKey) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
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 useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useMemo } from "react";
|
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 debug from "debug";
|
||||||
|
|
||||||
import { bech32ToHex, getNewest, getNewestEventTagsByKey, unwrap } from "SnortUtils";
|
import { bech32ToHex, getNewest, getNewestEventTagsByKey, unwrap } from "SnortUtils";
|
||||||
@ -7,7 +7,6 @@ import { makeNotification, sendNotification } from "Notifications";
|
|||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import { getMutedKeys } from "Feed/MuteList";
|
import { getMutedKeys } from "Feed/MuteList";
|
||||||
import useModeration from "Hooks/useModeration";
|
import useModeration from "Hooks/useModeration";
|
||||||
import { FlatNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import { DmCache } from "Cache";
|
import { DmCache } from "Cache";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import { useMemo } from "react";
|
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 { getNewest } from "SnortUtils";
|
||||||
import { ParameterizedReplaceableNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HexKey, Lists } from "System";
|
import { HexKey, Lists } from "@snort/system";
|
||||||
import useNotelistSubscription from "Hooks/useNotelistSubscription";
|
import useNotelistSubscription from "Hooks/useNotelistSubscription";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
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";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
|
|
||||||
export default function useRelaysFeed(pubkey?: HexKey) {
|
export default function useRelaysFeed(pubkey?: HexKey) {
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
import { useMemo } from "react";
|
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 debug from "debug";
|
||||||
|
|
||||||
import { sanitizeRelayUrl } from "SnortUtils";
|
import { sanitizeRelayUrl } from "SnortUtils";
|
||||||
import { PubkeyReplaceableNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import { UserRelays } from "Cache/UserRelayCache";
|
import { UserRelays } from "Cache/UserRelayCache";
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
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 { appendDedupe } from "SnortUtils";
|
||||||
import { FlatNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
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 { unixNow, unwrap, tagFilterOfTextRepost } from "SnortUtils";
|
||||||
import { FlatNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import useTimelineWindow from "Hooks/useTimelineWindow";
|
import useTimelineWindow from "Hooks/useTimelineWindow";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { HexKey, EventKind } from "System";
|
import { HexKey, EventKind, FlatNoteStore, RequestBuilder } from "@snort/system";
|
||||||
|
|
||||||
import { parseZap } from "Element/Zap";
|
import { parseZap } from "Element/Zap";
|
||||||
import { FlatNoteStore, RequestBuilder } from "System";
|
|
||||||
import useRequestBuilder from "Hooks/useRequestBuilder";
|
import useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
|
|
||||||
export default function useZapsFeed(pubkey?: HexKey) {
|
export default function useZapsFeed(pubkey?: HexKey) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
import { HexKey, u256 } from "System";
|
import { HexKey, u256 } from "@snort/system";
|
||||||
|
|
||||||
import { InteractionCache } from "Cache/EventInteractionCache";
|
import { InteractionCache } from "Cache/EventInteractionCache";
|
||||||
import { EventInteraction } from "Db";
|
import { EventInteraction } from "Db";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { setBlocked, setMuted } from "Login";
|
import { setBlocked, setMuted } from "Login";
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { useMemo } from "react";
|
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 useRequestBuilder from "Hooks/useRequestBuilder";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
import { RequestBuilder } from "System";
|
import { RequestBuilder, EmptySnapshot, NoteStore, StoreSnapshot } from "@snort/system";
|
||||||
import { EmptySnapshot, NoteStore, StoreSnapshot } from "System/NoteCollection";
|
|
||||||
import { unwrap } from "SnortUtils";
|
import { unwrap } from "SnortUtils";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
import { SystemSnapshot } from "System";
|
import { SystemSnapshot } from "@snort/system";
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
|
||||||
export default function useSystemState() {
|
export default function useSystemState() {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useEffect, useSyncExternalStore } from "react";
|
import { useEffect, useSyncExternalStore } from "react";
|
||||||
|
|
||||||
import { HexKey } from "System";
|
import { HexKey, MetadataCache } from "@snort/system";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
import { UserCache } from "Cache/UserCache";
|
import { UserCache } from "Cache/UserCache";
|
||||||
import { ProfileLoader } from "index";
|
import { ProfileLoader } from "index";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HexKey, NostrEvent } from "System";
|
import { HexKey, NostrEvent } from "@snort/system";
|
||||||
import { EmailRegex } from "Const";
|
import { EmailRegex } from "Const";
|
||||||
import { bech32ToText, unwrap } from "SnortUtils";
|
import { bech32ToText, unwrap } from "SnortUtils";
|
||||||
|
|
||||||
|
@ -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 secp from "@noble/curves/secp256k1";
|
||||||
import * as utils from "@noble/curves/abstract/utils";
|
import * as utils from "@noble/curves/abstract/utils";
|
||||||
|
|
||||||
@ -7,7 +7,6 @@ import { LoginStore, UserPreferences, LoginSession } from "Login";
|
|||||||
import { generateBip39Entropy, entropyToPrivateKey } from "nip6";
|
import { generateBip39Entropy, entropyToPrivateKey } from "nip6";
|
||||||
import { bech32ToHex, dedupeById, randomSample, sanitizeRelayUrl, unixNowMs, unwrap } from "SnortUtils";
|
import { bech32ToHex, dedupeById, randomSample, sanitizeRelayUrl, unixNowMs, unwrap } from "SnortUtils";
|
||||||
import { SubscriptionEvent } from "Subscription";
|
import { SubscriptionEvent } from "Subscription";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
|
||||||
import { System } from "index";
|
import { System } from "index";
|
||||||
|
|
||||||
export function setRelays(state: LoginSession, relays: Record<string, RelaySettings>, createdAt: number) {
|
export function setRelays(state: LoginSession, relays: Record<string, RelaySettings>, createdAt: number) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HexKey, RelaySettings, u256 } from "System";
|
import { HexKey, RelaySettings, u256 } from "@snort/system";
|
||||||
import { UserPreferences } from "Login";
|
import { UserPreferences } from "Login";
|
||||||
import { SubscriptionEvent } from "Subscription";
|
import { SubscriptionEvent } from "Subscription";
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as secp from "@noble/curves/secp256k1";
|
import * as secp from "@noble/curves/secp256k1";
|
||||||
import * as utils from "@noble/curves/abstract/utils";
|
import * as utils from "@noble/curves/abstract/utils";
|
||||||
|
|
||||||
import { HexKey, RelaySettings } from "System";
|
import { HexKey, RelaySettings } from "@snort/system";
|
||||||
|
|
||||||
import { DefaultRelays } from "Const";
|
import { DefaultRelays } from "Const";
|
||||||
import ExternalStore from "ExternalStore";
|
import ExternalStore from "ExternalStore";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { EventKind } from "System";
|
import { EventKind, EventPublisher } from "@snort/system";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
|
||||||
import { ServiceError, ServiceProvider } from "./ServiceProvider";
|
import { ServiceError, ServiceProvider } from "./ServiceProvider";
|
||||||
|
|
||||||
export interface ManageHandle {
|
export interface ManageHandle {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import Nostrich from "nostrich.webp";
|
import Nostrich from "nostrich.webp";
|
||||||
|
|
||||||
import { TaggedRawEvent, EventKind } from "System";
|
import { TaggedRawEvent, EventKind, MetadataCache } from "@snort/system";
|
||||||
import { MetadataCache } from "Cache";
|
|
||||||
import { getDisplayName } from "Element/ProfileImage";
|
import { getDisplayName } from "Element/ProfileImage";
|
||||||
import { MentionRegex } from "Const";
|
import { MentionRegex } from "Const";
|
||||||
import { tagFilterOfTextRepost, unwrap } from "SnortUtils";
|
import { tagFilterOfTextRepost, unwrap } from "SnortUtils";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import { ApiHost, KieranPubKey, SnortPubKey } from "Const";
|
import { ApiHost, KieranPubKey, SnortPubKey } from "Const";
|
||||||
import ProfilePreview from "Element/ProfilePreview";
|
import ProfilePreview from "Element/ProfilePreview";
|
||||||
|
@ -3,7 +3,7 @@ import "./LoginPage.css";
|
|||||||
import { CSSProperties, useEffect, useState } from "react";
|
import { CSSProperties, useEffect, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { HexKey } from "System";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import { bech32ToHex, unwrap } from "SnortUtils";
|
import { bech32ToHex, unwrap } from "SnortUtils";
|
||||||
import ZapButton from "Element/ZapButton";
|
import ZapButton from "Element/ZapButton";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
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 UnreadCount from "Element/UnreadCount";
|
||||||
import ProfileImage, { getDisplayName } from "Element/ProfileImage";
|
import ProfileImage, { getDisplayName } from "Element/ProfileImage";
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { NostrPrefix } from "System";
|
import { NostrPrefix, parseNostrLink } from "@snort/system";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import Spinner from "Icons/Spinner";
|
import Spinner from "Icons/Spinner";
|
||||||
import { parseNostrLink, profileLink } from "SnortUtils";
|
import { profileLink } from "SnortUtils";
|
||||||
import { getNip05PubKey } from "Pages/LoginPage";
|
import { getNip05PubKey } from "Pages/LoginPage";
|
||||||
|
|
||||||
export default function NostrLinkHandler() {
|
export default function NostrLinkHandler() {
|
||||||
|
@ -2,9 +2,9 @@ import "./ProfilePage.css";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
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 { formatShort } from "Number";
|
||||||
import Note from "Element/Note";
|
import Note from "Element/Note";
|
||||||
import Bookmarks from "Element/Bookmarks";
|
import Bookmarks from "Element/Bookmarks";
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
import { useIntl, FormattedMessage } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { mapEventToProfile } from "@snort/system";
|
||||||
|
|
||||||
import Logo from "Element/Logo";
|
import Logo from "Element/Logo";
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { mapEventToProfile, UserCache } from "Cache";
|
import { UserCache } from "Cache";
|
||||||
import AvatarEditor from "Element/AvatarEditor";
|
import AvatarEditor from "Element/AvatarEditor";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import "./Keys.css";
|
import "./Keys.css";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { encodeTLV, NostrPrefix } from "System";
|
import { encodeTLV, NostrPrefix } from "@snort/system";
|
||||||
|
|
||||||
import Copy from "Element/Copy";
|
import Copy from "Element/Copy";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
@ -3,13 +3,14 @@ import Nostrich from "nostrich.webp";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { mapEventToProfile } from "@snort/system";
|
||||||
|
|
||||||
import useEventPublisher from "Feed/EventPublisher";
|
import useEventPublisher from "Feed/EventPublisher";
|
||||||
import { useUserProfile } from "Hooks/useUserProfile";
|
import { useUserProfile } from "Hooks/useUserProfile";
|
||||||
import { openFile } from "SnortUtils";
|
import { openFile } from "SnortUtils";
|
||||||
import useFileUpload from "Upload";
|
import useFileUpload from "Upload";
|
||||||
import AsyncButton from "Element/AsyncButton";
|
import AsyncButton from "Element/AsyncButton";
|
||||||
import { mapEventToProfile, UserCache } from "Cache";
|
import { UserCache } from "Cache";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import AvatarEditor from "Element/AvatarEditor";
|
import AvatarEditor from "Element/AvatarEditor";
|
||||||
import Icon from "Icons/Icon";
|
import Icon from "Icons/Icon";
|
||||||
|
@ -23,7 +23,6 @@ const RelaySettingsPage = () => {
|
|||||||
if (publisher) {
|
if (publisher) {
|
||||||
const ev = await publisher.contactList(login.follows.item, login.relays.item);
|
const ev = await publisher.contactList(login.follows.item, login.relays.item);
|
||||||
publisher.broadcast(ev);
|
publisher.broadcast(ev);
|
||||||
publisher.broadcastForBootstrap(ev);
|
|
||||||
try {
|
try {
|
||||||
const onlineRelays = await fetch("https://api.nostr.watch/v1/online").then(r => r.json());
|
const onlineRelays = await fetch("https://api.nostr.watch/v1/online").then(r => r.json());
|
||||||
const relayList = await publisher.relayList(login.relays.item);
|
const relayList = await publisher.relayList(login.relays.item);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { EventKind } from "System";
|
import { EventKind, EventPublisher } from "@snort/system";
|
||||||
import { ApiHost } from "Const";
|
import { ApiHost } from "Const";
|
||||||
import { SubscriptionType } from "Subscription";
|
import { SubscriptionType } from "Subscription";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
|
||||||
|
|
||||||
export interface RevenueToday {
|
export interface RevenueToday {
|
||||||
donations: number;
|
donations: number;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { NostrPrefix } from "System";
|
import { NostrPrefix } from "@snort/system";
|
||||||
import { parseNostrLink, tryParseNostrLink } from ".";
|
|
||||||
import { splitByUrl, magnetURIDecode, getRelayName } from ".";
|
import { splitByUrl, magnetURIDecode, getRelayName } from ".";
|
||||||
import { describe, expect } from "@jest/globals";
|
import { describe, expect } from "@jest/globals";
|
||||||
|
|
||||||
@ -93,47 +92,3 @@ describe("getRelayName", () => {
|
|||||||
expect(output).toEqual("relay.example2.com?broadcast=true");
|
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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -13,12 +13,9 @@ import {
|
|||||||
EventKind,
|
EventKind,
|
||||||
encodeTLV,
|
encodeTLV,
|
||||||
NostrPrefix,
|
NostrPrefix,
|
||||||
decodeTLV,
|
|
||||||
TLVEntryType,
|
|
||||||
NostrEvent,
|
NostrEvent,
|
||||||
} from "System";
|
MetadataCache,
|
||||||
import { MetadataCache } from "Cache";
|
} from "@snort/system";
|
||||||
import NostrLink from "Element/NostrLink";
|
|
||||||
|
|
||||||
export const sha256 = (str: string | Uint8Array): u256 => {
|
export const sha256 = (str: string | Uint8Array): u256 => {
|
||||||
return utils.bytesToHex(hash(str));
|
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) {
|
export function sanitizeRelayUrl(url: string) {
|
||||||
try {
|
try {
|
||||||
return new URL(url).toString();
|
return new URL(url).toString();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { NostrEvent, TaggedRawEvent } from "System";
|
import { NostrEvent, TaggedRawEvent } from "@snort/system";
|
||||||
|
|
||||||
interface NoteCreatorStore {
|
interface NoteCreatorStore {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { NostrEvent } from "System";
|
import { NostrEvent } from "@snort/system";
|
||||||
|
|
||||||
interface ReBroadcastStore {
|
interface ReBroadcastStore {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
/**
|
|
||||||
* Websocket re-connect timeout
|
|
||||||
*/
|
|
||||||
export const DefaultConnectTimeout = 2000;
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,6 +1,6 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { MetadataCache } from "Cache";
|
import { MetadataCache } from "@snort/system";
|
||||||
import { BaseUITask } from "Tasks";
|
import { BaseUITask } from "Tasks";
|
||||||
|
|
||||||
export class Nip5Task extends BaseUITask {
|
export class Nip5Task extends BaseUITask {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { MetadataCache } from "Cache";
|
import { MetadataCache } from "@snort/system";
|
||||||
|
|
||||||
export interface UITask {
|
export interface UITask {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { EventKind } from "System";
|
import { EventKind, EventPublisher } from "@snort/system";
|
||||||
import { VoidApi } from "@void-cat/api";
|
import { VoidApi } from "@void-cat/api";
|
||||||
|
|
||||||
import { FileExtensionRegex, VoidCatHost } from "Const";
|
import { FileExtensionRegex, VoidCatHost } from "Const";
|
||||||
import { EventPublisher } from "System/EventPublisher";
|
|
||||||
import { UploadResult } from "Upload";
|
import { UploadResult } from "Upload";
|
||||||
import { magnetURIDecode } from "SnortUtils";
|
import { magnetURIDecode } from "SnortUtils";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { NostrEvent } from "System";
|
import { NostrEvent } from "@snort/system";
|
||||||
|
|
||||||
import NostrBuild from "Upload/NostrBuild";
|
import NostrBuild from "Upload/NostrBuild";
|
||||||
import VoidCat from "Upload/VoidCat";
|
import VoidCat from "Upload/VoidCat";
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { Connection, EventKind, NostrEvent } from "System";
|
import { Connection, EventKind, NostrEvent, EventBuilder, EventExt } from "@snort/system";
|
||||||
import { EventBuilder } from "System";
|
|
||||||
import { EventExt } from "System/EventExt";
|
|
||||||
import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "Wallet";
|
import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "Wallet";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
|
||||||
|
@ -33,10 +33,9 @@ import { SubscribeRoutes } from "Pages/subscribe";
|
|||||||
import ZapPoolPage from "Pages/ZapPool";
|
import ZapPoolPage from "Pages/ZapPool";
|
||||||
import DebugPage from "Pages/Debug";
|
import DebugPage from "Pages/Debug";
|
||||||
import { db } from "Db";
|
import { db } from "Db";
|
||||||
import { preload } from "Cache";
|
import { preload, UserCache } from "Cache";
|
||||||
import { LoginStore } from "Login";
|
import { LoginStore } from "Login";
|
||||||
import { ProfileLoaderService } from "System/ProfileCache";
|
import { NostrSystem, ProfileLoaderService } from "@snort/system";
|
||||||
import { NostrSystem } from "System";
|
|
||||||
import { UserRelays } from "Cache/UserRelayCache";
|
import { UserRelays } from "Cache/UserRelayCache";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +48,7 @@ export const System = new NostrSystem({
|
|||||||
/**
|
/**
|
||||||
* Singleton user profile loader
|
* Singleton user profile loader
|
||||||
*/
|
*/
|
||||||
export const ProfileLoader = new ProfileLoaderService(System);
|
export const ProfileLoader = new ProfileLoaderService(System, UserCache);
|
||||||
|
|
||||||
// @ts-expect-error Setting webpack nonce
|
// @ts-expect-error Setting webpack nonce
|
||||||
window.__webpack_nonce__ = "ZmlhdGphZiBzYWlkIHNub3J0LnNvY2lhbCBpcyBwcmV0dHkgZ29vZCwgd2UgbWFkZSBpdCE=";
|
window.__webpack_nonce__ = "ZmlhdGphZiBzYWlkIHNub3J0LnNvY2lhbCBpcyBwcmV0dHkgZ29vZCwgd2UgbWFkZSBpdCE=";
|
||||||
|
5
packages/system/.npmignore
Normal file
5
packages/system/.npmignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
tests/
|
||||||
|
src/
|
||||||
|
*.tgz
|
||||||
|
jest.config.js
|
||||||
|
worker.ts
|
90
packages/system/dist/Connection.d.ts
vendored
Normal file
90
packages/system/dist/Connection.d.ts
vendored
Normal file
@ -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<NostrEvent | undefined>;
|
||||||
|
/**
|
||||||
|
* 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<string>;
|
||||||
|
activeRequests: Array<string>;
|
||||||
|
id: string;
|
||||||
|
ephemeral: boolean;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
export declare class Connection extends ExternalStore<ConnectionStateSnapshot> {
|
||||||
|
#private;
|
||||||
|
Id: string;
|
||||||
|
Address: string;
|
||||||
|
Socket: WebSocket | null;
|
||||||
|
PendingRaw: Array<object>;
|
||||||
|
PendingRequests: Array<{
|
||||||
|
cmd: ReqCommand;
|
||||||
|
cb: () => void;
|
||||||
|
}>;
|
||||||
|
ActiveRequests: Set<string>;
|
||||||
|
Settings: RelaySettings;
|
||||||
|
Info?: RelayInfo;
|
||||||
|
ConnectTimeout: number;
|
||||||
|
Stats: ConnectionStats;
|
||||||
|
HasStateChange: boolean;
|
||||||
|
IsClosed: boolean;
|
||||||
|
ReconnectTimer: ReturnType<typeof setTimeout> | null;
|
||||||
|
EventsCallback: Map<u256, (msg: boolean[]) => void>;
|
||||||
|
OnConnected?: () => void;
|
||||||
|
OnEvent?: (sub: string, e: TaggedRawEvent) => void;
|
||||||
|
OnEose?: (sub: string) => void;
|
||||||
|
OnDisconnect?: (id: string) => void;
|
||||||
|
Auth?: AuthHandler;
|
||||||
|
AwaitingAuth: Map<string, boolean>;
|
||||||
|
Authed: boolean;
|
||||||
|
Ephemeral: boolean;
|
||||||
|
EphemeralTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
Down: boolean;
|
||||||
|
constructor(addr: string, options: RelaySettings, auth?: AuthHandler, ephemeral?: boolean);
|
||||||
|
ResetEphemeralTimeout(): void;
|
||||||
|
Connect(): Promise<void>;
|
||||||
|
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<void>;
|
||||||
|
/**
|
||||||
|
* 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<void>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=Connection.d.ts.map
|
1
packages/system/dist/Connection.d.ts.map
vendored
Normal file
1
packages/system/dist/Connection.d.ts.map
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../src/Connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,UAAW,SAAQ,aAAa,CAAC,uBAAuB,CAAC;;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;IAEhC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAM;IAC/B,eAAe,EAAE,KAAK,CAAC;QACrB,GAAG,EAAE,UAAU,CAAC;QAChB,EAAE,EAAE,MAAM,IAAI,CAAC;KAChB,CAAC,CAAM;IACR,cAAc,cAAqB;IAEnC,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,cAAc,EAAE,MAAM,CAAyB;IAC/C,KAAK,EAAE,eAAe,CAAyB;IAC/C,cAAc,EAAE,OAAO,CAAQ;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC;IACrD,cAAc,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;IACpD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IACnD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,UAAS;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAC;IAC5D,IAAI,UAAQ;gBAEA,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,WAAW,EAAE,SAAS,GAAE,OAAe;IAahG,qBAAqB;IAWf,OAAO;IAsCb,KAAK;IAUL,MAAM;IAWN,OAAO,CAAC,CAAC,EAAE,UAAU;IAwBrB,SAAS,CAAC,CAAC,EAAE,YAAY;IAiDzB,OAAO,CAAC,CAAC,EAAE,KAAK;IAKhB;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,UAAU;IAUvB;;OAEG;IACG,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,SAAO;IAqB7C;;OAEG;IACH,WAAW,CAAC,CAAC,EAAE,MAAM;IAIrB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,IAAI;IAe5C,QAAQ,CAAC,EAAE,EAAE,MAAM;IASnB,YAAY,IAAI,uBAAuB;IA2EjC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoCrD"}
|
343
packages/system/dist/Connection.js
vendored
Normal file
343
packages/system/dist/Connection.js
vendored
Normal file
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user