feat: relay detail page
This commit is contained in:
parent
8db0a02384
commit
e75245fec8
@ -10,6 +10,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@snort/shared": "^1.0.10",
|
||||
"@snort/system": "^1.1.8",
|
||||
"@snort/system-react": "^1.1.8",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.21.1"
|
||||
|
@ -1,8 +1,20 @@
|
||||
import { HTMLProps } from "react";
|
||||
import { HTMLProps, useState } from "react";
|
||||
import Spinner from "./spinner";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export default function Button({ children, type, ...props }: HTMLProps<HTMLButtonElement>) {
|
||||
return <button {...props} type="button" className="py-2 px-3 rounded-xl bg-slate-700 border border-slate-500 hover:bg-slate-600 hover:bg-slate-400 animate min-w-20">
|
||||
{children}
|
||||
export default function Button({ children, type, onClick, ...props }: Omit<HTMLProps<HTMLButtonElement>, "onClick"> & {
|
||||
onClick?: (e: React.MouseEvent) => Promise<void>
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
return <button {...props} type="button" className="py-2 px-3 rounded-xl bg-slate-700 border border-slate-500 hover:bg-slate-600 hover:bg-slate-400 animate min-w-20 relative" onClick={async e => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await onClick?.(e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}}>
|
||||
{loading && <span className="absolute w-full h-full top-0 left-0 flex items-center justify-center"><Spinner /></span>}
|
||||
<span className={loading ? "invisible" : ""}>{children}</span>
|
||||
</button>
|
||||
}
|
74
src/element/event.tsx
Normal file
74
src/element/event.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { hexToBech32 } from "@snort/shared";
|
||||
import { EventKind, NostrEvent, transformText } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import { useMemo } from "react";
|
||||
import { Mention } from "./mention";
|
||||
|
||||
export function SimpleEvent({ ev }: { ev: NostrEvent }) {
|
||||
const profile = useUserProfile(ev.pubkey);
|
||||
|
||||
function renderContent() {
|
||||
switch (ev.kind) {
|
||||
case EventKind.TextNote: return <TextNote ev={ev} />
|
||||
case EventKind.SetMetadata: return "Profile Update";
|
||||
case EventKind.Reaction: return ev.content;
|
||||
case EventKind.DirectMessage: return <div>
|
||||
DM with <Mention pubkey={ev.tags.find(a => a[0] === "p")![1]} />
|
||||
</div>;
|
||||
case EventKind.ZapReceipt: return <div>
|
||||
Zapping <Mention pubkey={ev.tags.find(a => a[0] === "p")![1]} />
|
||||
</div>
|
||||
case EventKind.ContactList: return <div>
|
||||
Following: {ev.tags.filter(a => a[0] === "p").length.toLocaleString()}
|
||||
</div>;
|
||||
case EventKind.Repost: return "";
|
||||
case EventKind.Relays: return ev.tags.filter(a => a[0] === "r").map(a => a[1]).join(", ");
|
||||
default: return <pre>{JSON.stringify(ev, undefined, 2)}</pre>;
|
||||
}
|
||||
}
|
||||
|
||||
function kindName() {
|
||||
switch (ev.kind) {
|
||||
case 0: return "Profile";
|
||||
case 1: return "TextNote";
|
||||
case 3: return "Contact List";
|
||||
case 4: return "DM";
|
||||
case 5: return "Deletion";
|
||||
case 6: return "Repost";
|
||||
case 7: return "Reaction";
|
||||
case 10_002: return "Relays";
|
||||
case 9735: return "Zap";
|
||||
default: return `Kind ${ev.kind}`;
|
||||
}
|
||||
}
|
||||
return <div className="p-3 rounded-xl bg-slate-800 flex flex-col gap-2 max-h-[20vh] overflow-hidden">
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="rounded-full aspect-square w-10 h-10 bg-slate-700 object-cover overflow-hidden">
|
||||
<img src={profile?.picture} loading="lazy" />
|
||||
</div>
|
||||
<div>
|
||||
{profile?.display_name ?? profile?.name ?? hexToBech32("npub", ev.pubkey).slice(0, 12)}
|
||||
</div>
|
||||
<div className="text-slate-400">
|
||||
{kindName()}
|
||||
</div>
|
||||
</div>
|
||||
{renderContent()}
|
||||
</div>
|
||||
}
|
||||
|
||||
function TextNote({ ev }: { ev: NostrEvent }) {
|
||||
const fragments = useMemo(() => transformText(ev.content, ev.tags), [ev.content, ev.tags]);
|
||||
return <div>{fragments.map((f, i) => {
|
||||
switch (f.type) {
|
||||
case "link":
|
||||
case "media": {
|
||||
return <a key={i} href={f.content}>{f.content}</a>
|
||||
}
|
||||
default: {
|
||||
return <span key={i} className="text-pretty">{f.content}</span>
|
||||
}
|
||||
}
|
||||
})}
|
||||
</div>;
|
||||
}
|
11
src/element/mention.tsx
Normal file
11
src/element/mention.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { hexToBech32 } from "@snort/shared";
|
||||
import { NostrLink, NostrPrefix } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export function Mention({ pubkey }: { pubkey: string }) {
|
||||
const profile = useUserProfile(pubkey);
|
||||
return <Link to={`nostr:${new NostrLink(NostrPrefix.PublicKey, pubkey).encode()}`}>
|
||||
{profile?.display_name ?? profile?.name ?? hexToBech32("npub", pubkey).slice(0, 12)}
|
||||
</Link>
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Relay } from "../api";
|
||||
|
||||
export default function RelayItem({ relay, index }: { relay: Relay, index: number }) {
|
||||
const navigate = useNavigate();
|
||||
const kv = (key: string, value: string) => {
|
||||
return <div className="flex-1">
|
||||
<span className="text-slate-400">{key}: </span>
|
||||
@ -8,16 +10,27 @@ export default function RelayItem({ relay, index }: { relay: Relay, index: numbe
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div className="px-2 py-3 rounded-xl bg-slate-800 flex flex-col gap-2">
|
||||
const u = new URL(relay.url);
|
||||
|
||||
return <div className="p-3 rounded-xl bg-slate-800 flex flex-col gap-2 cursor-pointer select-none hover:bg-slate-700 animate" onClick={() => {
|
||||
navigate(`/r/${encodeURIComponent(relay.url)}`);
|
||||
}}>
|
||||
<div className="text-lg flex gap-2 items-center">
|
||||
<div className="text-slate-500 text-xl">#{index + 1}</div>
|
||||
<div>{relay.url}</div>
|
||||
<div className="text-slate-400 text-xl">#{index + 1}</div>
|
||||
<div>
|
||||
<span className="text-slate-400">{u.protocol}//</span>
|
||||
<span className="font-medium">{u.host}{u.pathname !== "/" ? u.pathname : ""}</span>
|
||||
</div>
|
||||
{relay.description && <div className="text-xs text-slate-400">{relay.description}</div>}
|
||||
</div>
|
||||
<div className="flex">
|
||||
{kv("Users", relay.users.toLocaleString())}
|
||||
{relay.country && kv("Country", relay.country)}
|
||||
<div>
|
||||
<div className="flex gap-2">
|
||||
{relay.distance !== 0 && <div className="flex gap-1 items-center">
|
||||
<span>{Math.ceil(relay.distance / 1000).toLocaleString()}</span>
|
||||
<span className="text-xs text-slate-400">Km</span>
|
||||
</div>}
|
||||
{relay.is_paid === true ? <span className="text-orange-400">Paid</span> : <span className="text-green-400">Free</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
34
src/element/spinner.css
Normal file
34
src/element/spinner.css
Normal file
@ -0,0 +1,34 @@
|
||||
.spinner_V8m1 {
|
||||
transform-origin: center;
|
||||
animation: spinner_zKoa 2s linear infinite;
|
||||
}
|
||||
|
||||
.spinner_V8m1 circle {
|
||||
stroke-linecap: round;
|
||||
animation: spinner_YpZS 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner_zKoa {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spinner_YpZS {
|
||||
0% {
|
||||
stroke-dasharray: 0 150;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
47.5% {
|
||||
stroke-dasharray: 42 150;
|
||||
stroke-dashoffset: -16;
|
||||
}
|
||||
|
||||
95%,
|
||||
100% {
|
||||
stroke-dasharray: 42 150;
|
||||
stroke-dashoffset: -59;
|
||||
}
|
||||
}
|
||||
|
17
src/element/spinner.tsx
Normal file
17
src/element/spinner.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import "./spinner.css";
|
||||
|
||||
export interface IconProps {
|
||||
className?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
const Spinner = (props: IconProps) => (
|
||||
<svg width="20" height="20" stroke="currentColor" viewBox="0 0 20 20" {...props}>
|
||||
<g className="spinner_V8m1">
|
||||
<circle cx="10" cy="10" r="7.5" fill="none" strokeWidth="3"></circle>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Spinner;
|
@ -2,6 +2,23 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
body,
|
||||
html,
|
||||
:host {
|
||||
@apply text-white bg-slate-950;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-red-300;
|
||||
}
|
@ -6,7 +6,9 @@ export default function Layout() {
|
||||
return <div className="mx-auto max-w-[1024px]">
|
||||
<header className="py-4 flex gap-4 items-center">
|
||||
<div className="text-xl font-semibold">Snort Relays</div>
|
||||
<Button>
|
||||
<Button onClick={async () => {
|
||||
navigate("/");
|
||||
}}>
|
||||
Top
|
||||
</Button>
|
||||
<Button onClick={async () => {
|
||||
|
23
src/main.tsx
23
src/main.tsx
@ -4,14 +4,31 @@ import './index.css'
|
||||
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
|
||||
import Layout from './layout'
|
||||
import RelayListPage from './pages/relay-list'
|
||||
import { RelayDetailPage } from './pages/relay-detail'
|
||||
import { NostrSystem } from '@snort/system'
|
||||
import { SnortContext } from '@snort/system-react'
|
||||
|
||||
const system = new NostrSystem({});
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
element: <Layout />,
|
||||
loader: async () => {
|
||||
await system.Init();
|
||||
return null;
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
element: <RelayListPage />
|
||||
},
|
||||
{
|
||||
path: "/closest",
|
||||
element: <RelayListPage />
|
||||
},
|
||||
{
|
||||
path: "/r/:relay",
|
||||
element: <RelayDetailPage />
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -19,8 +36,8 @@ const router = createBrowserRouter([
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<RouterProvider router={router}>
|
||||
|
||||
</RouterProvider>
|
||||
<SnortContext.Provider value={system}>
|
||||
<RouterProvider router={router} />
|
||||
</SnortContext.Provider>
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
45
src/pages/relay-detail.tsx
Normal file
45
src/pages/relay-detail.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { SnortContext, useRequestBuilder } from "@snort/system-react";
|
||||
import { useContext, useEffect, useMemo } from "react";
|
||||
import { useParams } from "react-router-dom"
|
||||
import { SimpleEvent } from "../element/event";
|
||||
import { sanitizeRelayUrl } from "@snort/shared";
|
||||
|
||||
export function RelayDetailPage() {
|
||||
const { relay } = useParams();
|
||||
const system = useContext(SnortContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (relay) {
|
||||
system.ConnectToRelay(relay, {
|
||||
read: true,
|
||||
write: false
|
||||
});
|
||||
return () => system.DisconnectRelay(relay);
|
||||
}
|
||||
}, [system, relay]);
|
||||
|
||||
const sub = useMemo(() => {
|
||||
if (relay) {
|
||||
const rb = new RequestBuilder(`events:${relay}`);
|
||||
rb.withOptions({ leaveOpen: true })
|
||||
rb.withFilter().limit(10).relay(relay);
|
||||
return rb;
|
||||
}
|
||||
return null;
|
||||
}, [relay]);
|
||||
const events = useRequestBuilder(NoteCollection, sub);
|
||||
|
||||
return <div className="flex flex-col gap-5">
|
||||
<h1>{relay}</h1>
|
||||
<div>
|
||||
<pre className="bg-slate-800 rounded-xl p-3">
|
||||
{JSON.stringify(system.Sockets.find(a => a.address === sanitizeRelayUrl(relay!)!)?.info, undefined, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
<h2>Latest Events</h2>
|
||||
<div className="flex flex-col gap-1">
|
||||
{events.data?.sort((a, b) => a.created_at > b.created_at ? -1 : 1).slice(0, 10).map(a => <SimpleEvent ev={a} key={a.id} />)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
@ -1,16 +1,24 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Relay, SnortApi } from "../api";
|
||||
import RelayItem from "../element/relay";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
export default function RelayListPage() {
|
||||
const { state } = useLocation();
|
||||
const [relays, setRelays] = useState<Array<Relay>>();
|
||||
|
||||
useEffect(() => {
|
||||
const api = new SnortApi();
|
||||
api.topRelays(100).then(setRelays);
|
||||
}, []);
|
||||
if (state) {
|
||||
const { lat, lon } = state;
|
||||
api.closeRelays(lat, lon, 100).then(setRelays);
|
||||
} else {
|
||||
api.topRelays(100).then(setRelays);
|
||||
|
||||
}
|
||||
}, [state]);
|
||||
|
||||
return <div className="flex flex-col gap-2">
|
||||
{relays?.map((a, i) => <RelayItem relay={a} index={i} />)}
|
||||
{relays?.map((a, i) => <RelayItem relay={a} index={i} key={a.url} />)}
|
||||
</div>;
|
||||
}
|
@ -10,7 +10,6 @@
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
|
168
yarn.lock
168
yarn.lock
@ -567,6 +567,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@noble/curves@npm:^1.2.0":
|
||||
version: 1.3.0
|
||||
resolution: "@noble/curves@npm:1.3.0"
|
||||
dependencies:
|
||||
"@noble/hashes": "npm:1.3.3"
|
||||
checksum: 704bf8fda8e1365a9bb9e9945bd06645ef4ce85aa2fac5594abe09f19889197518152319481b89a271e0ee011787bd2ee87202441500bca7ca587a2c3ac10b01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@noble/hashes@npm:1.3.3, @noble/hashes@npm:^1.3.2":
|
||||
version: 1.3.3
|
||||
resolution: "@noble/hashes@npm:1.3.3"
|
||||
checksum: 23c020b33da4172c988e44100e33cd9f8f6250b68b43c467d3551f82070ebd9716e0d9d2347427aa3774c85934a35fa9ee6f026fca2117e3fa12db7bedae7668
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nodelib/fs.scandir@npm:2.1.5":
|
||||
version: 2.1.5
|
||||
resolution: "@nodelib/fs.scandir@npm:2.1.5"
|
||||
@ -721,6 +737,106 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@scure/base@npm:1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "@scure/base@npm:1.1.1"
|
||||
checksum: 97d200da8915ca18a4eceb73c23dda7fc3a4b8509f620c9b7756ee451d7c9ebbc828c6662f9ffa047806fbe41f37bf236c6ef75692690688b7659196cb2dc804
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@scure/base@npm:^1.1.2":
|
||||
version: 1.1.5
|
||||
resolution: "@scure/base@npm:1.1.5"
|
||||
checksum: 6eb07be0202fac74a57c79d0d00a45f6f7e57447010c1e3d90a4275d197829727b7abc54b248fc6f9bef9ae374f7be5ee9154dde5b5b73da773560bf17aa8504
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@snort/shared@npm:^1.0.10":
|
||||
version: 1.0.10
|
||||
resolution: "@snort/shared@npm:1.0.10"
|
||||
dependencies:
|
||||
"@noble/curves": "npm:^1.2.0"
|
||||
"@noble/hashes": "npm:^1.3.2"
|
||||
"@scure/base": "npm:^1.1.2"
|
||||
debug: "npm:^4.3.4"
|
||||
light-bolt11-decoder: "npm:^3.0.0"
|
||||
checksum: 66196cfa46fab8a58f230cf84073cdadbcea586328b7778c92dc30c39636214cc2cade9beb9fd680e919f29f842cca8b2fecb5b8c38719e0ec6fc9c1b3d79502
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@snort/system-react@npm:^1.1.8":
|
||||
version: 1.1.8
|
||||
resolution: "@snort/system-react@npm:1.1.8"
|
||||
dependencies:
|
||||
"@snort/shared": "npm:^1.0.10"
|
||||
"@snort/system": "npm:^1.1.8"
|
||||
react: "npm:^18.2.0"
|
||||
checksum: 2fb819be58850e742b7fb50efc76c5ae798fbd4d62e6bf5a1d563625385f72ebb52264c17cd9e746cab356cbc5f29001d01f002ebf13473cf2197dac710839c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@snort/system@npm:^1.1.8":
|
||||
version: 1.1.8
|
||||
resolution: "@snort/system@npm:1.1.8"
|
||||
dependencies:
|
||||
"@noble/curves": "npm:^1.2.0"
|
||||
"@noble/hashes": "npm:^1.3.2"
|
||||
"@scure/base": "npm:^1.1.2"
|
||||
"@snort/shared": "npm:^1.0.10"
|
||||
"@stablelib/xchacha20": "npm:^1.0.1"
|
||||
debug: "npm:^4.3.4"
|
||||
eventemitter3: "npm:^5.0.1"
|
||||
isomorphic-ws: "npm:^5.0.0"
|
||||
uuid: "npm:^9.0.0"
|
||||
ws: "npm:^8.14.0"
|
||||
checksum: 1772d2227a9baabe8715541de2c5e71d10e6ddfcc4ffc1672a5d30cac3c81ad3779e0cf2145345b170a4cd287d5bb3d3a2ac3bbe1bea7d64c2735700e5bed963
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@stablelib/binary@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@stablelib/binary@npm:1.0.1"
|
||||
dependencies:
|
||||
"@stablelib/int": "npm:^1.0.1"
|
||||
checksum: 154cb558d8b7c20ca5dc2e38abca2a3716ce36429bf1b9c298939cea0929766ed954feb8a9c59245ac64c923d5d3466bb7d99f281debd3a9d561e1279b11cd35
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@stablelib/chacha@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@stablelib/chacha@npm:1.0.1"
|
||||
dependencies:
|
||||
"@stablelib/binary": "npm:^1.0.1"
|
||||
"@stablelib/wipe": "npm:^1.0.1"
|
||||
checksum: 4d70b484ae89416d21504024f977f5517bf16b344b10fb98382c9e3e52fe8ca77ac65f5d6a358d8b152f2c9ffed101a1eb15ed1707cdf906e1b6624db78d2d16
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@stablelib/int@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@stablelib/int@npm:1.0.1"
|
||||
checksum: e1a6a7792fc2146d65de56e4ef42e8bc385dd5157eff27019b84476f564a1a6c43413235ed0e9f7c9bb8907dbdab24679467aeb10f44c92e6b944bcd864a7ee0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@stablelib/wipe@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@stablelib/wipe@npm:1.0.1"
|
||||
checksum: c5a54f769c286a5b3ecff979471dfccd4311f2e84a959908e8c0e3aa4eed1364bd9707f7b69d1384b757e62cc295c221fa27286c7f782410eb8a690f30cfd796
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@stablelib/xchacha20@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@stablelib/xchacha20@npm:1.0.1"
|
||||
dependencies:
|
||||
"@stablelib/binary": "npm:^1.0.1"
|
||||
"@stablelib/chacha": "npm:^1.0.1"
|
||||
"@stablelib/wipe": "npm:^1.0.1"
|
||||
checksum: 7b72e9ebf414b3ea9355c2c780dd992e62ede3d4839ca0f8e8b980d4bbe9af9216fde31b1f7ebd7bd38de120fe74b0c99d8628b7bcdeac820e91df09c2618002
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/babel__core@npm:^7.20.5":
|
||||
version: 7.20.5
|
||||
resolution: "@types/babel__core@npm:7.20.5"
|
||||
@ -1666,6 +1782,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eventemitter3@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "eventemitter3@npm:5.0.1"
|
||||
checksum: 4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"exponential-backoff@npm:^3.1.1":
|
||||
version: 3.1.1
|
||||
resolution: "exponential-backoff@npm:3.1.1"
|
||||
@ -2118,6 +2241,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"isomorphic-ws@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "isomorphic-ws@npm:5.0.0"
|
||||
peerDependencies:
|
||||
ws: "*"
|
||||
checksum: a058ac8b5e6efe9e46252cb0bc67fd325005d7216451d1a51238bc62d7da8486f828ef017df54ddf742e0fffcbe4b1bcc2a66cc115b027ed0180334cd18df252
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jackspeak@npm:^2.3.5":
|
||||
version: 2.3.6
|
||||
resolution: "jackspeak@npm:2.3.6"
|
||||
@ -2216,6 +2348,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"light-bolt11-decoder@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "light-bolt11-decoder@npm:3.0.0"
|
||||
dependencies:
|
||||
"@scure/base": "npm:1.1.1"
|
||||
checksum: e08e2b02d2025606fd39411eb8aa2070e0d3058897f9d07ad02a17ba71412910ab903a7eac4c1220cde935aa2ab26eeebb040f3efe0aab485bdf45015ee2185c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lilconfig@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "lilconfig@npm:2.1.0"
|
||||
@ -2868,6 +3009,9 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "relays@workspace:."
|
||||
dependencies:
|
||||
"@snort/shared": "npm:^1.0.10"
|
||||
"@snort/system": "npm:^1.1.8"
|
||||
"@snort/system-react": "npm:^1.1.8"
|
||||
"@types/react": "npm:^18.2.43"
|
||||
"@types/react-dom": "npm:^18.2.17"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^6.14.0"
|
||||
@ -3395,6 +3539,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"uuid@npm:^9.0.0":
|
||||
version: 9.0.1
|
||||
resolution: "uuid@npm:9.0.1"
|
||||
bin:
|
||||
uuid: dist/bin/uuid
|
||||
checksum: 1607dd32ac7fc22f2d8f77051e6a64845c9bce5cd3dd8aa0070c074ec73e666a1f63c7b4e0f4bf2bc8b9d59dc85a15e17807446d9d2b17c8485fbc2147b27f9b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.0.8":
|
||||
version: 5.0.10
|
||||
resolution: "vite@npm:5.0.10"
|
||||
@ -3486,6 +3639,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ws@npm:^8.14.0":
|
||||
version: 8.16.0
|
||||
resolution: "ws@npm:8.16.0"
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: ">=5.0.2"
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
checksum: a7783bb421c648b1e622b423409cb2a58ac5839521d2f689e84bc9dc41d59379c692dd405b15a997ea1d4c0c2e5314ad707332d0c558f15232d2bc07c0b4618a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yallist@npm:^3.0.2":
|
||||
version: 3.1.1
|
||||
resolution: "yallist@npm:3.1.1"
|
||||
|
Loading…
Reference in New Issue
Block a user