refactor: upgrade snort pkgs

This commit is contained in:
Kieran 2023-10-16 23:05:37 +01:00
parent d9bcea518b
commit b36c305a53
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
57 changed files with 389 additions and 1094 deletions

View File

@ -14,9 +14,10 @@
"@radix-ui/react-toggle": "^1.0.3",
"@react-hook/resize-observer": "^1.2.6",
"@scure/base": "^1.1.1",
"@snort/shared": "^1.0.5",
"@snort/system": "^1.0.18",
"@snort/system-react": "^1.0.13",
"@snort/shared": "^1.0.8",
"@snort/system": "^1.0.22",
"@snort/system-react": "^1.0.19",
"@snort/system-web": "^1.0.1",
"@szhsin/react-menu": "^4.0.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
@ -30,6 +31,7 @@
"hls.js": "^1.4.6",
"lodash": "^4.17.21",
"lodash.uniqby": "^4.7.0",
"marked": "^9.1.2",
"moment": "^2.29.4",
"qr-code-styling": "^1.6.0-rc.1",
"react": "^18.2.0",
@ -40,7 +42,6 @@
"react-helmet": "^6.1.0",
"react-intersection-observer": "^9.5.1",
"react-intl": "^6.4.4",
"react-markdown": "^8.0.7",
"react-router-dom": "^6.13.0",
"react-tag-input-component": "^2.0.2",
"semantic-sdp": "^3.26.3",

View File

@ -1,7 +1,8 @@
import { useUserProfile, SnortContext } from "@snort/system-react";
import { NostrEvent, parseZap, EventKind } from "@snort/system";
import { useUserProfile, SnortContext, useEventReactions } from "@snort/system-react";
import { EventKind, NostrLink, TaggedNostrEvent } from "@snort/system";
import React, { useRef, useState, useMemo, useContext } from "react";
import { useMediaQuery, useHover, useOnClickOutside, useIntersectionObserver } from "usehooks-ts";
import { dedupe } from "@snort/shared";
import { EmojiPicker } from "element/emoji-picker";
import { Icon } from "element/icon";
@ -13,7 +14,6 @@ import { SendZapsDialog } from "element/send-zap";
import { CollapsibleEvent } from "element/collapsible";
import { useLogin } from "hooks/login";
import { formatSats } from "number";
import { findTag } from "utils";
import type { Badge, Emoji, EmojiPack } from "types";
function emojifyReaction(reaction: string) {
@ -26,28 +26,26 @@ function emojifyReaction(reaction: string) {
return reaction;
}
const customComponents = {
Event: CollapsibleEvent,
};
export function ChatMessage({
streamer,
ev,
reactions,
related,
emojiPacks,
badges,
}: {
ev: NostrEvent;
ev: TaggedNostrEvent;
streamer: string;
reactions: readonly NostrEvent[];
related: ReadonlyArray<TaggedNostrEvent>;
emojiPacks: EmojiPack[];
badges: Badge[];
}) {
const system = useContext(SnortContext);
const ref = useRef<HTMLDivElement | null>(null);
const inView = useIntersectionObserver(ref, {
freezeOnceVisible: true,
});
const emojiRef = useRef(null);
const link = NostrLink.fromEvent(ev);
const isTablet = useMediaQuery("(max-width: 1020px)");
const isHovering = useHover(ref);
const { mute } = useMute(ev.pubkey);
@ -57,25 +55,16 @@ export function ChatMessage({
const profile = useUserProfile(inView?.isIntersecting ? ev.pubkey : undefined);
const shouldShowMuteButton = ev.pubkey !== streamer && ev.pubkey !== login?.pubkey;
const zapTarget = profile?.lud16 ?? profile?.lud06;
const system = useContext(SnortContext);
const zaps = useMemo(() => {
return reactions
.filter(a => a.kind === EventKind.ZapReceipt)
.map(a => parseZap(a, system.ProfileLoader.Cache))
.filter(a => a && a.valid);
}, [reactions]);
const emojiReactions = useMemo(() => {
const emojified = reactions
.filter(e => e.kind === EventKind.Reaction && findTag(e, "e") === ev.id)
.map(ev => emojifyReaction(ev.content));
return [...new Set(emojified)];
}, [ev, reactions]);
const { zaps, reactions } = useEventReactions(ev, related);
const emojiNames = emojiPacks.map(p => p.emojis).flat();
const hasReactions = emojiReactions.length > 0;
const filteredReactions = useMemo(() => {
return reactions.all.filter(a => link.isReplyToThis(a));
}, [ev, reactions.all]);
const hasReactions = filteredReactions.length > 0;
const totalZaps = useMemo(() => {
const messageZaps = zaps.filter(z => z.event === ev.id);
return messageZaps.reduce((acc, z) => acc + z.amount, 0);
return zaps.filter(a => a.event?.id === ev.id).reduce((acc, z) => acc + z.amount, 0);
}, [zaps, ev]);
const hasZaps = totalZaps > 0;
const awardedBadges = badges.filter(b => b.awardees.has(ev.pubkey) && b.accepted.has(ev.pubkey));
@ -153,7 +142,7 @@ export function ChatMessage({
pubkey={ev.pubkey}
profile={profile}
/>
<Text tags={ev.tags} content={ev.content} customComponents={customComponents} />
<Text tags={ev.tags} content={ev.content} eventComponent={CollapsibleEvent} />
{(hasReactions || hasZaps) && (
<div className="message-reactions">
{hasZaps && (
@ -162,7 +151,7 @@ export function ChatMessage({
<span className="zap-pill-amount">{formatSats(totalZaps)}</span>
</div>
)}
{emojiReactions.map(e => {
{dedupe(filteredReactions.map(v => emojifyReaction(v.content))).map(e => {
const isCustomEmojiReaction = e.length > 1 && e.startsWith(":") && e.endsWith(":");
const emojiName = e.replace(/:/g, "");
const emoji = isCustomEmojiReaction && getEmojiById(emojiName);

View File

@ -6,11 +6,14 @@ import { toEmojiPack } from "hooks/emoji";
import AsyncButton from "element/async-button";
import { findTag } from "utils";
import { USER_EMOJIS } from "const";
import { Login, System } from "index";
import { Login } from "index";
import type { EmojiPack as EmojiPackType } from "types";
import { FormattedMessage } from "react-intl";
import { useContext } from "react";
import { SnortContext } from "@snort/system-react";
export function EmojiPack({ ev }: { ev: NostrEvent }) {
const system = useContext(SnortContext);
const login = useLogin();
const name = findTag(ev, "d");
const isUsed = login?.emojis.find(e => e.author === ev.pubkey && e.name === name);
@ -33,7 +36,7 @@ export function EmojiPack({ ev }: { ev: NostrEvent }) {
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
Login.setEmojis(newPacks);
}
}
@ -55,7 +58,7 @@ export function EmojiPack({ ev }: { ev: NostrEvent }) {
const [, name, image] = e;
return (
<div className="emoji-definition">
<img alt={name} className="emoji" src={image} />
<img alt={name} className="custom-emoji" src={image} />
<span className="emoji-name">{name}</span>
</div>
);

View File

@ -1,4 +1,4 @@
.emoji {
.custom-emoji {
width: 21px;
height: 21px;
display: inline-block;

View File

@ -8,7 +8,7 @@ export type EmojiProps = {
};
export function Emoji({ name, url }: EmojiProps) {
return <img alt={name} src={url} className="emoji" />;
return <img alt={name} src={url} className="custom-emoji" />;
}
export function Emojify({ content, emoji }: { content: string; emoji: EmojiTag[] }) {

View File

@ -2,10 +2,13 @@ import { EventKind } from "@snort/system";
import { useLogin } from "hooks/login";
import AsyncButton from "element/async-button";
import { Login, System } from "index";
import { Login } from "index";
import { FormattedMessage } from "react-intl";
import { useContext } from "react";
import { SnortContext } from "@snort/system-react";
export function LoggedInFollowButton({ tag, value }: { tag: "p" | "t"; value: string }) {
const system = useContext(SnortContext);
const login = useLogin();
if (!login) return;
@ -25,7 +28,7 @@ export function LoggedInFollowButton({ tag, value }: { tag: "p" | "t"; value: st
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
Login.setFollows(newFollows, content ?? "", ev.created_at);
}
}
@ -42,7 +45,7 @@ export function LoggedInFollowButton({ tag, value }: { tag: "p" | "t"; value: st
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
Login.setFollows(newFollows, content ?? "", ev.created_at);
}
}

View File

@ -3,10 +3,10 @@ import { useMemo } from "react";
import * as Progress from "@radix-ui/react-progress";
import Confetti from "react-confetti";
import { type NostrEvent } from "@snort/system";
import { NostrLink, type NostrEvent } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { eventToLink, findTag } from "utils";
import { findTag } from "utils";
import { formatSats } from "number";
import usePreviousValue from "hooks/usePreviousValue";
import { SendZapsDialog } from "element/send-zap";
@ -18,7 +18,7 @@ import { useZaps } from "hooks/zaps";
export function Goal({ ev }: { ev: NostrEvent }) {
const profile = useUserProfile(ev.pubkey);
const zapTarget = profile?.lud16 ?? profile?.lud06;
const link = eventToLink(ev);
const link = NostrLink.fromEvent(ev);
const zaps = useZaps(link, true);
const goalAmount = useMemo(() => {
const amount = findTag(ev, "amount");
@ -30,7 +30,7 @@ export function Goal({ ev }: { ev: NostrEvent }) {
}
const soFar = useMemo(() => {
return zaps.filter(z => z.receiver === ev.pubkey && z.event === ev.id).reduce((acc, z) => acc + z.amount, 0);
return zaps.filter(z => z.receiver === ev.pubkey && z.event?.id === ev.id).reduce((acc, z) => acc + z.amount, 0);
}, [zaps]);
const progress = Math.max(0, Math.min(100, (soFar / goalAmount) * 100));

View File

@ -6,7 +6,7 @@ const FileExtensionRegex = /\.([\w]+)$/i;
interface HyperTextProps {
link: string;
children: ReactNode;
children?: ReactNode;
}
export function HyperText({ link, children }: HyperTextProps) {

View File

@ -2,7 +2,7 @@ import "./live-chat.css";
import { FormattedMessage } from "react-intl";
import { EventKind, NostrPrefix, NostrLink, ParsedZap, NostrEvent, parseZap, encodeTLV } from "@snort/system";
import { unixNow } from "@snort/shared";
import { useMemo } from "react";
import { useContext, useMemo } from "react";
import uniqBy from "lodash.uniqby";
import { Icon } from "element/icon";
@ -22,8 +22,8 @@ import { useAddress } from "hooks/event";
import { formatSats } from "number";
import { WEEK, LIVE_STREAM_CHAT } from "const";
import { findTag, getTagValues, getHost } from "utils";
import { System } from "index";
import { TopZappers } from "element/top-zappers";
import { SnortContext } from "@snort/system-react";
export interface LiveChatOptions {
canWrite?: boolean;
@ -61,6 +61,7 @@ export function LiveChat({
options?: LiveChatOptions;
height?: number;
}) {
const system = useContext(SnortContext);
const host = getHost(ev);
const feed = useLiveChatFeed(link, goal ? [goal.id] : undefined);
const login = useLogin();
@ -79,7 +80,7 @@ export function LiveChat({
return uniqBy(userEmojiPacks.concat(channelEmojiPacks), packId);
}, [userEmojiPacks, channelEmojiPacks]);
const zaps = feed.zaps.map(ev => parseZap(ev, System.ProfileLoader.Cache)).filter(z => z && z.valid);
const zaps = feed.zaps.map(ev => parseZap(ev, system.ProfileLoader.Cache)).filter(z => z && z.valid);
const events = useMemo(() => {
return [...feed.messages, ...feed.zaps, ...awards].sort((a, b) => b.created_at - a.created_at);
}, [feed.messages, feed.zaps, awards]);
@ -132,7 +133,7 @@ export function LiveChat({
streamer={host}
ev={a}
key={a.id}
reactions={feed.reactions}
related={feed.reactions}
/>
);
}

View File

@ -10,19 +10,20 @@ import LoginKey2x from "../login-key@2x.jpg";
import LoginWallet from "../login-wallet.jpg";
import LoginWallet2x from "../login-wallet@2x.jpg";
import { CSSProperties, useState } from "react";
import { CSSProperties, useContext, useState } from "react";
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";
import { EventPublisher, UserMetadata } from "@snort/system";
import { schnorr } from "@noble/curves/secp256k1";
import { bytesToHex } from "@noble/curves/abstract/utils";
import { LNURL, bech32ToHex, getPublicKey } from "@snort/shared";
import { LNURL, bech32ToHex, getPublicKey, hexToBech32 } from "@snort/shared";
import { VoidApi } from "@void-cat/api";
import { SnortContext } from "@snort/system-react";
import AsyncButton from "./async-button";
import { Login, System } from "index";
import { Login } from "index";
import { Icon } from "./icon";
import Copy from "./copy";
import { hexToBech32, openFile } from "utils";
import { openFile } from "utils";
import { LoginType } from "login";
import { DefaultProvider, StreamProviderInfo } from "providers";
import { Nip103StreamProvider } from "providers/zsz";
@ -36,6 +37,7 @@ enum Stage {
}
export function LoginSignup({ close }: { close: () => void }) {
const system = useContext(SnortContext);
const [error, setError] = useState("");
const [stage, setStage] = useState(Stage.Login);
const [username, setUsername] = useState("");
@ -136,7 +138,7 @@ export function LoginSignup({ close }: { close: () => void }) {
const ev = await pub.metadata(profile);
console.debug(ev);
System.BroadcastEvent(ev);
system.BroadcastEvent(ev);
setStage(Stage.SaveKey);
} catch (e) {

View File

@ -1,20 +1,37 @@
.markdown a {
color: var(--text-link);
}
.markdown > ul,
.markdown > ol {
margin: 0;
padding: 0 12px;
.markdown {
font-size: 18px;
font-weight: 400;
line-height: 29px;
}
.markdown > p {
font-size: 18px;
font-style: normal;
overflow-wrap: break-word;
font-weight: 400;
line-height: 29px; /* 161.111% */
.markdown a {
color: var(--text-link);
}
.markdown blockquote {
margin: 0;
color: var(--font-secondary-color);
border-left: 2px solid var(--font-secondary-color);
padding-left: 12px;
}
.markdown hr {
border: 0;
height: 1px;
background-image: var(--gray-gradient);
margin: 20px;
}
.markdown img:not(.custom-emoji),
.markdown video,
.markdown iframe,
.markdown audio {
width: 100%;
display: block;
}
.markdown iframe,
.markdown video {
width: -webkit-fill-available;
aspect-ratio: 16 / 9;
}

View File

@ -1,49 +1,95 @@
import "./markdown.css";
import { useMemo } from "react";
import ReactMarkdown from "react-markdown";
import { HyperText } from "element/hypertext";
import { transformText, type Fragment } from "element/text";
import type { Tags } from "types";
import { ReactNode, forwardRef, useMemo } from "react";
import { marked, Token } from "marked";
import { HyperText } from "./hypertext";
import { Text } from "./text";
interface MarkdownProps {
content: string;
tags?: Tags;
tags?: Array<Array<string>>;
}
interface LinkProps {
href?: string;
children?: Array<Fragment>;
function renderToken(t: Token): ReactNode {
try {
switch (t.type) {
case "paragraph": {
return <p>{t.tokens ? t.tokens.map(renderToken) : t.raw}</p>;
}
case "image": {
return <img src={t.href} />;
}
case "heading": {
switch (t.depth) {
case 1:
return <h1>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h1>;
case 2:
return <h2>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h2>;
case 3:
return <h3>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h3>;
case 4:
return <h4>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h4>;
case 5:
return <h5>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h5>;
case 6:
return <h6>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h6>;
}
throw new Error("Invalid heading");
}
case "codespan": {
return <code>{t.raw}</code>;
}
case "code": {
return <pre>{t.raw}</pre>;
}
case "br": {
return <br />;
}
case "hr": {
return <hr />;
}
case "blockquote": {
return <blockquote>{t.tokens ? t.tokens.map(renderToken) : t.raw}</blockquote>;
}
case "link": {
return <HyperText link={t.href}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</HyperText>;
}
case "list": {
if (t.ordered) {
return <ol>{t.items.map(renderToken)}</ol>;
} else {
return <ul>{t.items.map(renderToken)}</ul>;
}
}
case "list_item": {
return <li>{t.tokens ? t.tokens.map(renderToken) : t.raw}</li>;
}
case "em": {
return <em>{t.tokens ? t.tokens.map(renderToken) : t.raw}</em>;
}
case "del": {
return <s>{t.tokens ? t.tokens.map(renderToken) : t.raw}</s>;
}
default: {
if ("tokens" in t) {
return (t.tokens as Array<Token>).map(renderToken);
}
return <Text content={t.raw} tags={[]} />;
}
}
} catch (e) {
console.error(e);
}
}
interface ComponentProps {
children?: Array<Fragment>;
}
export const Markdown = forwardRef<HTMLDivElement, MarkdownProps>((props: MarkdownProps, ref) => {
const parsed = useMemo(() => {
return marked.lexer(props.content);
}, [props.content, props.tags]);
export function Markdown({ content, tags = [] }: MarkdownProps) {
const components = useMemo(() => {
return {
li: ({ children, ...props }: ComponentProps) => {
return children && <li {...props}>{transformText(children, tags)}</li>;
},
td: ({ children }: ComponentProps) => {
return children && <td>{transformText(children, tags)}</td>;
},
th: ({ children }: ComponentProps) => {
return children && <th>{transformText(children, tags)}</th>;
},
p: ({ children }: ComponentProps) => {
return children && <p>{transformText(children, tags)}</p>;
},
a: ({ href, children }: LinkProps) => {
return href && <HyperText link={href}>{children}</HyperText>;
},
};
}, [tags]);
return (
<div className="markdown">
<ReactMarkdown components={components}>{content}</ReactMarkdown>
<div className="markdown" ref={ref}>
{parsed.filter(a => a.type !== "footnote" && a.type !== "footnotes").map(a => renderToken(a))}
</div>
);
}
});

View File

@ -1,6 +1,6 @@
import { Link } from "react-router-dom";
import { useUserProfile } from "@snort/system-react";
import { hexToBech32 } from "utils";
import { hexToBech32 } from "@snort/shared";
interface MentionProps {
pubkey: string;

View File

@ -1,11 +1,13 @@
import { useMemo } from "react";
import { useContext, useMemo } from "react";
import { useLogin } from "hooks/login";
import AsyncButton from "element/async-button";
import { Login, System } from "index";
import { Login } from "index";
import { MUTED } from "const";
import { FormattedMessage } from "react-intl";
import { SnortContext } from "@snort/system-react";
export function useMute(pubkey: string) {
const system = useContext(SnortContext);
const login = useLogin();
const { tags, content } = login?.muted ?? { tags: [] };
const muted = useMemo(() => tags.filter(t => t.at(0) === "p"), [tags]);
@ -23,7 +25,7 @@ export function useMute(pubkey: string) {
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
Login.setMuted(newMuted, content ?? "", ev.created_at);
}
}
@ -40,7 +42,7 @@ export function useMute(pubkey: string) {
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
Login.setMuted(newMuted, content ?? "", ev.created_at);
}
}

View File

@ -3,14 +3,15 @@ import * as Dialog from "@radix-ui/react-dialog";
import AsyncButton from "./async-button";
import { Icon } from "element/icon";
import { useState } from "react";
import { System } from "index";
import { useContext, useState } from "react";
import { GOAL } from "const";
import { useLogin } from "hooks/login";
import { FormattedMessage } from "react-intl";
import { defaultRelays } from "const";
import { SnortContext } from "@snort/system-react";
export function NewGoalDialog() {
const system = useContext(SnortContext);
const [open, setOpen] = useState(false);
const login = useLogin();
@ -28,7 +29,7 @@ export function NewGoalDialog() {
return eb;
});
console.debug(evNew);
System.BroadcastEvent(evNew);
await system.BroadcastEvent(evNew);
setOpen(false);
setGoalName("");
setGoalAmount("");

View File

@ -4,15 +4,17 @@ import * as Dialog from "@radix-ui/react-dialog";
import { Icon } from "element/icon";
import { useStreamProvider } from "hooks/stream-provider";
import { StreamProvider, StreamProviders } from "providers";
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import { StreamEditor, StreamEditorProps } from "./stream-editor";
import { useNavigate } from "react-router-dom";
import { eventLink, findTag } from "utils";
import { NostrProviderDialog } from "./nostr-provider-dialog";
import { unwrap } from "@snort/shared";
import { FormattedMessage } from "react-intl";
import { SnortContext } from "@snort/system-react";
function NewStream({ ev, onFinish }: StreamEditorProps) {
const system = useContext(SnortContext);
const providers = useStreamProvider();
const [currentProvider, setCurrentProvider] = useState<StreamProvider>();
const navigate = useNavigate();
@ -33,7 +35,7 @@ function NewStream({ ev, onFinish }: StreamEditorProps) {
return (
<StreamEditor
onFinish={ex => {
currentProvider.updateStreamInfo(ex);
currentProvider.updateStreamInfo(system, ex);
if (!ev) {
if (findTag(ex, "content-warning") && __XXX_HOST && __XXX === false) {
location.href = `${__XXX_HOST}/${eventLink(ex)}`;

View File

@ -1,13 +1,15 @@
import { NostrEvent } from "@snort/system";
import { StreamProvider, StreamProviderEndpoint, StreamProviderInfo } from "providers";
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import { SendZaps } from "./send-zap";
import { StreamEditor, StreamEditorProps } from "./stream-editor";
import Spinner from "./spinner";
import AsyncButton from "./async-button";
import { FormattedMessage } from "react-intl";
import { SnortContext } from "@snort/system-react";
export function NostrProviderDialog({ provider, ...others }: { provider: StreamProvider } & StreamEditorProps) {
const system = useContext(SnortContext);
const [topup, setTopup] = useState(false);
const [info, setInfo] = useState<StreamProviderInfo>();
const [ep, setEndpoint] = useState<StreamProviderEndpoint>();
@ -181,7 +183,7 @@ export function NostrProviderDialog({ provider, ...others }: { provider: StreamP
) : (
<StreamEditor
onFinish={ex => {
provider.updateStreamInfo(ex);
provider.updateStreamInfo(system, ex);
others.onFinish?.(ex);
}}
ev={

View File

@ -4,7 +4,7 @@ import { type NostrEvent, NostrPrefix } from "@snort/system";
import { Markdown } from "element/markdown";
import { ExternalIconLink } from "element/external-link";
import { Profile } from "element/profile";
import { hexToBech32 } from "utils";
import { hexToBech32 } from "@snort/shared";
export function Note({ ev }: { ev: NostrEvent }) {
return (

View File

@ -4,17 +4,18 @@ import { unwrap } from "@snort/shared";
import { NostrEvent, NostrPrefix, encodeTLV } from "@snort/system";
import { Icon } from "./icon";
import { useState } from "react";
import { useContext, useState } from "react";
import { Textarea } from "./textarea";
import { findTag } from "utils";
import AsyncButton from "./async-button";
import { useLogin } from "hooks/login";
import { System } from "index";
import { FormattedMessage } from "react-intl";
import { SnortContext } from "@snort/system-react";
type ShareOn = "nostr" | "twitter";
export function ShareMenu({ ev }: { ev: NostrEvent }) {
const system = useContext(SnortContext);
const [share, setShare] = useState<ShareOn>();
const [message, setMessage] = useState("");
const login = useLogin();
@ -27,7 +28,7 @@ export function ShareMenu({ ev }: { ev: NostrEvent }) {
if (pub) {
const ev = await pub.note(message);
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
setShare(undefined);
}
}

View File

@ -1,12 +1,13 @@
import "./stream-cards.css";
import { useState, forwardRef } from "react";
import { useState, forwardRef, useContext } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import * as Dialog from "@radix-ui/react-dialog";
import { DndProvider, useDrag, useDrop } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { TaggedNostrEvent } from "@snort/system";
import { removeUndefined, unwrap } from "@snort/shared";
import { NostrLink, TaggedNostrEvent } from "@snort/system";
import { Toggle } from "element/toggle";
import { Icon } from "element/icon";
@ -16,9 +17,10 @@ import { Markdown } from "element/markdown";
import { useLogin } from "hooks/login";
import { useCards, useUserCards } from "hooks/cards";
import { CARD, USER_CARDS } from "const";
import { toTag, findTag } from "utils";
import { Login, System } from "index";
import { findTag } from "utils";
import { Login } from "index";
import type { Tags } from "types";
import { SnortContext } from "@snort/system-react";
interface CardType {
identifier: string;
@ -71,6 +73,7 @@ interface CardItem {
}
function Card({ canEdit, ev, cards }: CardProps) {
const system = useContext(SnortContext);
const login = useLogin();
const identifier = findTag(ev, "d") ?? "";
const title = findTag(ev, "title") || findTag(ev, "subject");
@ -78,7 +81,7 @@ function Card({ canEdit, ev, cards }: CardProps) {
const link = findTag(ev, "r");
const content = ev.content;
const evCard = { title, image, link, content, identifier };
const tags = cards.map(toTag);
const tags = removeUndefined(cards.map(a => NostrLink.fromEvent(a).toEventTag()));
const [style, dragRef] = useDrag(
() => ({
type: "card",
@ -140,7 +143,7 @@ function Card({ canEdit, ev, cards }: CardProps) {
return eb;
});
console.debug(userCardsEv);
System.BroadcastEvent(userCardsEv);
await system.BroadcastEvent(userCardsEv);
Login.setCards(newTags, userCardsEv.created_at);
}
},
@ -255,10 +258,11 @@ interface EditCardProps {
}
function EditCard({ card, cards }: EditCardProps) {
const system = useContext(SnortContext);
const login = useLogin();
const [isOpen, setIsOpen] = useState(false);
const identifier = card.identifier;
const tags = cards.map(toTag);
const tags = removeUndefined(cards.map(a => NostrLink.fromEvent(a).toEventTag()));
const { formatMessage } = useIntl();
async function editCard({ title, image, link, content }: CardType) {
@ -278,7 +282,7 @@ function EditCard({ card, cards }: EditCardProps) {
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
await system.BroadcastEvent(ev);
setIsOpen(false);
}
}
@ -296,7 +300,7 @@ function EditCard({ card, cards }: EditCardProps) {
});
console.debug(userCardsEv);
System.BroadcastEvent(userCardsEv);
await system.BroadcastEvent(userCardsEv);
Login.setCards(newTags, userCardsEv.created_at);
setIsOpen(false);
}
@ -333,8 +337,9 @@ interface AddCardProps {
}
function AddCard({ cards }: AddCardProps) {
const system = useContext(SnortContext);
const login = useLogin();
const tags = cards.map(toTag);
const tags = removeUndefined(cards.map(a => NostrLink.fromEvent(a).toEventTag()));
const [isOpen, setIsOpen] = useState(false);
async function createCard({ title, image, link, content }: NewCard) {
@ -356,18 +361,16 @@ function AddCard({ cards }: AddCardProps) {
});
const userCardsEv = await pub.generic(eb => {
eb.kind(USER_CARDS).content("");
for (const tag of tags) {
eb.tag(tag);
}
eb.tag(toTag(ev));
tags.forEach(a => eb.tag(a));
eb.tag(unwrap(NostrLink.fromEvent(ev).toEventTag()));
return eb;
});
console.debug(ev);
console.debug(userCardsEv);
System.BroadcastEvent(ev);
System.BroadcastEvent(userCardsEv);
await system.BroadcastEvent(ev);
await system.BroadcastEvent(userCardsEv);
setIsOpen(false);
}
}

View File

@ -1,207 +1,52 @@
import { useMemo, type ReactNode, type FunctionComponent } from "react";
import { NostrLink, NostrPrefix, ParsedFragment, transformText, tryParseNostrLink } from "@snort/system";
import { FunctionComponent, useMemo } from "react";
import { type NostrLink, parseNostrLink, validateNostrLink } from "@snort/system";
import { Emoji } from "./emoji";
import { Mention } from "./mention";
import { HyperText } from "./hypertext";
import { Event } from "./Event";
import { Event } from "element/Event";
import { Mention } from "element/mention";
import { Emoji } from "element/emoji";
import { HyperText } from "element/hypertext";
import { splitByUrl } from "utils";
import type { Tags } from "types";
export type Fragment = string | ReactNode;
const NostrPrefixRegex = /^nostr:/;
const EmojiRegex = /:([\w-]+):/g;
function extractLinks(fragments: Fragment[]) {
return fragments
.map(f => {
if (typeof f === "string") {
return splitByUrl(f).map(a => {
const validateLink = () => {
const normalizedStr = a.toLowerCase();
if (normalizedStr.startsWith("web+nostr:") || normalizedStr.startsWith("nostr:")) {
return validateNostrLink(normalizedStr);
}
return normalizedStr.startsWith("http:") || normalizedStr.startsWith("https:");
};
if (validateLink()) {
return <HyperText link={a}>{a}</HyperText>;
}
return a;
});
}
return f;
})
.flat();
}
function extractEmoji(fragments: Fragment[], tags: string[][]) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(EmojiRegex).map(i => {
const t = tags.find(a => a[0] === "emoji" && a[1] === i);
if (t) {
return <Emoji name={t[1]} url={t[2]} />;
} else {
return i;
}
});
}
return f;
})
.flat();
}
function extractNprofiles(fragments: Fragment[]) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(/(nostr:nprofile1[a-z0-9]+)/g).map(i => {
if (i.startsWith("nostr:nprofile1")) {
try {
const link = parseNostrLink(i.replace(NostrPrefixRegex, ""));
return <Mention key={link.id} pubkey={link.id} />;
} catch (error) {
return i;
}
} else {
return i;
}
});
}
return f;
})
.flat();
}
function extractNpubs(fragments: Fragment[]) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(/(nostr:npub1[a-z0-9]+)/g).map(i => {
if (i.startsWith("nostr:npub1")) {
try {
const link = parseNostrLink(i.replace(NostrPrefixRegex, ""));
return <Mention key={link.id} pubkey={link.id} />;
} catch (error) {
return i;
}
} else {
return i;
}
});
}
return f;
})
.flat();
}
function extractNevents(fragments: Fragment[], Event: NostrComponent) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(/(nostr:nevent1[a-z0-9]+)/g).map(i => {
if (i.startsWith("nostr:nevent1")) {
try {
const link = parseNostrLink(i.replace(NostrPrefixRegex, ""));
return <Event link={link} />;
} catch (error) {
return i;
}
} else {
return i;
}
});
}
return f;
})
.flat();
}
function extractNaddrs(fragments: Fragment[], Address: NostrComponent) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(/(nostr:naddr1[a-z0-9]+)/g).map(i => {
if (i.startsWith("nostr:naddr1")) {
try {
const link = parseNostrLink(i.replace(NostrPrefixRegex, ""));
return <Address key={i} link={link} />;
} catch (error) {
console.error(error);
return i;
}
} else {
return i;
}
});
}
return f;
})
.flat();
}
function extractNoteIds(fragments: Fragment[], Event: NostrComponent) {
return fragments
.map(f => {
if (typeof f === "string") {
return f.split(/(nostr:note1[a-z0-9]+)/g).map(i => {
if (i.startsWith("nostr:note1")) {
try {
const link = parseNostrLink(i.replace(NostrPrefixRegex, ""));
return <Event link={link} />;
} catch (error) {
return i;
}
} else {
return i;
}
});
}
return f;
})
.flat();
}
export type NostrComponent = FunctionComponent<{ link: NostrLink }>;
export interface NostrComponents {
Event: NostrComponent;
}
const components: NostrComponents = {
Event,
};
export function transformText(ps: Fragment[], tags: Array<string[]>, customComponents = components) {
let fragments = extractEmoji(ps, tags);
fragments = extractNprofiles(fragments);
fragments = extractNevents(fragments, customComponents.Event);
fragments = extractNaddrs(fragments, customComponents.Event);
fragments = extractNoteIds(fragments, customComponents.Event);
fragments = extractNpubs(fragments);
fragments = extractLinks(fragments);
return fragments;
}
export type EventComponent = FunctionComponent<{ link: NostrLink }>;
interface TextProps {
content: string;
tags: Tags;
customComponents?: NostrComponents;
tags: Array<Array<string>>;
eventComponent?: EventComponent;
}
export function Text({ content, tags, customComponents }: TextProps) {
// todo: RTL langugage support
const element = useMemo(() => {
return <span className="text">{transformText([content], tags, customComponents)}</span>;
export function Text({ content, tags, eventComponent }: TextProps) {
const frags = useMemo(() => {
return transformText(content, tags);
}, [content, tags]);
return <>{element}</>;
function renderFrag(f: ParsedFragment) {
switch (f.type) {
case "custom_emoji":
return <Emoji name="" url={f.content} />;
case "media":
case "link": {
if (f.content.startsWith("nostr:")) {
const link = tryParseNostrLink(f.content);
if (link) {
if (
link.type === NostrPrefix.Event ||
link?.type === NostrPrefix.Address ||
link?.type === NostrPrefix.Note
) {
return eventComponent?.({ link }) ?? <Event link={link} />;
} else {
return <Mention pubkey={link.id} />;
}
}
}
return <HyperText link={f.content} />;
}
case "mention":
return <Mention pubkey={f.content} />;
default:
return <span className="text">{f.content}</span>;
}
}
return frags.map(renderFrag);
}

View File

@ -1,17 +1,17 @@
import "./textarea.css";
import type { KeyboardEvent, ChangeEvent } from "react";
import { type KeyboardEvent, type ChangeEvent, useContext } from "react";
import ReactTextareaAutocomplete, { TriggerType } from "@webscopeio/react-textarea-autocomplete";
import "@webscopeio/react-textarea-autocomplete/style.css";
import uniqWith from "lodash/uniqWith";
import isEqual from "lodash/isEqual";
import { hexToBech32 } from "@snort/shared";
import { SnortContext } from "@snort/system-react";
import { MetadataCache, NostrPrefix, UserProfileCache } from "@snort/system";
import { Emoji } from "element/emoji";
import { Avatar } from "element/avatar";
import { hexToBech32 } from "utils";
import type { EmojiTag } from "types";
import { System } from "index";
interface EmojiItemProps {
name: string;
@ -48,8 +48,9 @@ interface TextareaProps {
}
export function Textarea({ emojis, ...props }: TextareaProps) {
const system = useContext(SnortContext);
const userDataProvider = async (token: string) => {
const cache = System.ProfileLoader.Cache;
const cache = system.ProfileLoader.Cache;
if (cache instanceof UserProfileCache) {
return await cache.search(token);
}

View File

@ -1,5 +1,5 @@
import { NostrLink, EventKind } from "@snort/system";
import React, { useRef, useState } from "react";
import React, { useContext, useRef, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useLogin } from "hooks/login";
@ -8,10 +8,11 @@ import { Icon } from "element/icon";
import { Textarea } from "element/textarea";
import { EmojiPicker } from "element/emoji-picker";
import type { EmojiPack, Emoji } from "types";
import { System } from "index";
import { LIVE_STREAM_CHAT } from "const";
import { SnortContext } from "@snort/system-react";
export function WriteMessage({ link, emojiPacks }: { link: NostrLink; emojiPacks: EmojiPack[] }) {
const system = useContext(SnortContext);
const ref = useRef<HTMLDivElement | null>(null);
const emojiRef = useRef(null);
const [chat, setChat] = useState("");
@ -49,7 +50,7 @@ export function WriteMessage({ link, emojiPacks }: { link: NostrLink; emojiPacks
});
if (reply) {
console.debug(reply);
System.BroadcastEvent(reply);
system.BroadcastEvent(reply);
}
setChat("");
}

View File

@ -1,11 +1,11 @@
import { useMemo } from "react";
import { useContext, useMemo } from "react";
import { RequestBuilder, NoteCollection, NostrLink, EventKind, parseZap } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { SnortContext, useRequestBuilder } from "@snort/system-react";
import { LIVE_STREAM } from "const";
import { findTag } from "utils";
import { System } from "index";
export function useProfile(link: NostrLink, leaveOpen = false) {
const system = useContext(SnortContext);
const sub = useMemo(() => {
const b = new RequestBuilder(`profile:${link.id.slice(0, 12)}`);
b.withOptions({
@ -43,7 +43,7 @@ export function useProfile(link: NostrLink, leaveOpen = false) {
const { data: zapsData } = useRequestBuilder(NoteCollection, zapsSub);
const zaps = (zapsData ?? [])
.map(ev => parseZap(ev, System.ProfileLoader.Cache))
.map(ev => parseZap(ev, system.ProfileLoader.Cache))
.filter(z => z && z.valid && z.receiver === link.id);
const sortedStreams = useMemo(() => {

View File

@ -1,8 +1,7 @@
import { useContext, useMemo, useEffect } from "react";
import { unwrap } from "@snort/shared";
import { NostrLink, RequestBuilder, NostrPrefix, EventKind, NoteCollection, parseZap } from "@snort/system";
import { SnortContext, useRequestBuilder } from "@snort/system-react";
import { System } from "index";
import { useContext, useMemo, useEffect } from "react";
import { findTag } from "utils";
export function useZaps(link?: NostrLink, leaveOpen = false) {
@ -34,7 +33,7 @@ export function useZaps(link?: NostrLink, leaveOpen = false) {
return (
[...(zaps ?? [])]
.sort((a, b) => (b.created_at > a.created_at ? 1 : -1))
.map(ev => parseZap(ev, System.ProfileLoader.Cache))
.map(ev => parseZap(ev, system.ProfileLoader.Cache))
.filter(z => z && z.valid) ?? []
);
}

View File

@ -341,7 +341,7 @@ div.paper {
background-color: unset;
}
.emoji {
.custom-emoji {
width: 15px;
height: 15px;
margin-bottom: -2px;

View File

@ -6,6 +6,7 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { NostrSystem } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { SnortSystemDb } from "@snort/system-web";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { RootPage } from "pages/root";
@ -30,7 +31,11 @@ export enum StreamState {
Planned = "planned",
}
export const System = new NostrSystem({});
const db = new SnortSystemDb();
const System = new NostrSystem({
db,
checkSigs: false,
});
export const Login = new LoginStore();
register();
@ -44,6 +49,7 @@ const router = createBrowserRouter([
{
element: <LayoutPage />,
loader: async () => {
db.ready = await db.isAvailable();
await System.Init();
return null;
},
@ -86,6 +92,7 @@ const router = createBrowserRouter([
path: "/chat/:id",
element: <ChatPopout />,
loader: async () => {
db.ready = await db.isAvailable();
await System.Init();
return null;
},
@ -94,6 +101,7 @@ const router = createBrowserRouter([
path: "/alert/:id/:type",
element: <AlertsPage />,
loader: async () => {
db.ready = await db.isAvailable();
await System.Init();
return null;
},

View File

@ -4,16 +4,16 @@ import { useLocation, useNavigate } from "react-router-dom";
import { Helmet } from "react-helmet";
import { LiveVideoPlayer } from "element/live-video-player";
import { eventToLink, findTag, getEventFromLocationState, getHost } from "utils";
import { findTag, getEventFromLocationState, getHost } from "utils";
import { Profile, getName } from "element/profile";
import { LiveChat } from "element/live-chat";
import AsyncButton from "element/async-button";
import { useLogin } from "hooks/login";
import { useZapGoal } from "hooks/goals";
import { StreamState, System } from "index";
import { StreamState } from "index";
import { SendZapsDialog } from "element/send-zap";
import { NostrEvent } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { SnortContext, useUserProfile } from "@snort/system-react";
import { NewStreamDialog } from "element/new-stream";
import { Tags } from "element/tags";
import { StatePill } from "element/state-pill";
@ -25,8 +25,10 @@ import { ContentWarningOverlay, isContentWarningAccepted } from "element/content
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
import { useStreamLink } from "hooks/stream-link";
import { FormattedMessage } from "react-intl";
import { useContext } from "react";
function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedNostrEvent }) {
const system = useContext(SnortContext);
const login = useLogin();
const navigate = useNavigate();
const host = getHost(ev);
@ -41,7 +43,7 @@ function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedNostrEvent })
if (pub && ev) {
const evDelete = await pub.delete(ev.id);
console.debug(evDelete);
System.BroadcastEvent(evDelete);
await system.BroadcastEvent(evDelete);
navigate("/");
}
}
@ -113,7 +115,7 @@ export function StreamPageHandler() {
export function StreamPage({ link, evPreload }: { evPreload?: NostrEvent; link: NostrLink }) {
const ev = useCurrentStreamFeed(link, true, evPreload);
const host = getHost(ev);
const evLink = ev ? eventToLink(ev) : undefined;
const evLink = ev ? NostrLink.fromEvent(ev) : undefined;
const goal = useZapGoal(findTag(ev, "goal"));
const title = findTag(ev, "title");

View File

@ -2,18 +2,18 @@
import "./widgets.css";
import { useState, useMemo } from "react";
import { useIntl, FormattedMessage } from "react-intl";
import { NostrLink, NostrPrefix } from "@snort/system";
import { NostrPrefix, createNostrLink } from "@snort/system";
import Copy from "element/copy";
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
import { getVoices, speak, toTextToSpeechParams } from "text2speech";
import { useLogin } from "hooks/login";
import { eventToLink, hexToBech32 } from "utils";
import { ZapAlertItem } from "./widgets/zaps";
import { TopZappersWidget } from "./widgets/top-zappers";
import { Views } from "./widgets/views";
import { Music } from "./widgets/music";
import groupBy from "lodash/groupBy";
import { hexToBech32 } from "@snort/shared";
interface ZapAlertConfigurationProps {
npub: string;
@ -164,9 +164,9 @@ function ZapAlertConfiguration({ npub, baseUrl }: ZapAlertConfigurationProps) {
export function WidgetsPage() {
const login = useLogin();
const profileLink = createNostrLink(NostrPrefix.PublicKey, login?.pubkey ?? "");
const profileLink = new NostrLink(NostrPrefix.PublicKey, login?.pubkey ?? "");
const current = useCurrentStreamFeed(profileLink);
const currentLink = current ? eventToLink(current) : undefined;
const currentLink = current ? NostrLink.fromEvent(current) : undefined;
const npub = hexToBech32("npub", login?.pubkey);
const baseUrl = `${window.location.protocol}//${window.location.host}`;

View File

@ -12,7 +12,8 @@ export function Music({ link }: { link: NostrLink }) {
const expiry = nowPlaying && findTag(nowPlaying, "expiration");
const isExpired = expiry && Number(expiry) < unixNow();
return (
(nowPlaying && !isExpired) && (
nowPlaying &&
!isExpired && (
<div className="music">
{cover && <img className="cover" src={cover} alt={nowPlaying.content} />}
{nowPlaying && <p className="track">🎵 {nowPlaying.content}</p>}

View File

@ -3,11 +3,10 @@ import { TopZappers } from "element/top-zappers";
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
import { useZaps } from "hooks/zaps";
import { FormattedMessage } from "react-intl";
import { eventToLink } from "utils";
export function TopZappersWidget({ link }: { link: NostrLink }) {
const currentEvent = useCurrentStreamFeed(link, true);
const zaps = useZaps(currentEvent ? eventToLink(currentEvent) : undefined, true);
const zaps = useZaps(currentEvent ? NostrLink.fromEvent(currentEvent) : undefined, true);
return (
<div className="top-zappers-widget">
<div>

View File

@ -1,7 +1,7 @@
import { useMemo, useState, useEffect } from "react";
import { hexToBech32 } from "@snort/shared";
import type { NostrLink, ParsedZap } from "@snort/system";
import { NostrLink, ParsedZap } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
@ -10,7 +10,7 @@ import { useMutedPubkeys } from "hooks/lists";
import { formatSats } from "number";
import { useTextToSpeechParams, getVoices, speak } from "text2speech";
import { FormattedMessage } from "react-intl";
import { getHost, eventToLink } from "utils";
import { getHost } from "utils";
function useZapQueue(zapStream: ParsedZap[], zapTime = 10_000) {
const zaps = useMemo(() => {
@ -34,7 +34,7 @@ function useZapQueue(zapStream: ParsedZap[], zapTime = 10_000) {
export function ZapAlerts({ link }: { link: NostrLink }) {
const currentEvent = useCurrentStreamFeed(link, true);
const currentLink = currentEvent ? eventToLink(currentEvent) : undefined;
const currentLink = currentEvent ? NostrLink.fromEvent(currentEvent) : undefined;
const host = getHost(currentEvent);
const zaps = useZaps(currentLink, true);
const zap = useZapQueue(zaps);

View File

@ -1,5 +1,5 @@
import { StreamState } from "index";
import { NostrEvent } from "@snort/system";
import { NostrEvent, SystemInterface } from "@snort/system";
import { ExternalStore } from "@snort/shared";
import { Nip103StreamProvider } from "./zsz";
import { ManualProvider } from "./manual";
@ -22,7 +22,7 @@ export interface StreamProvider {
/**
* Update stream info event
*/
updateStreamInfo(ev: NostrEvent): Promise<void>;
updateStreamInfo(system: SystemInterface, ev: NostrEvent): Promise<void>;
/**
* Top-up balance with provider

View File

@ -1,5 +1,4 @@
import { NostrEvent } from "@snort/system";
import { System } from "index";
import { NostrEvent, SystemInterface } from "@snort/system";
import { StreamProvider, StreamProviderInfo, StreamProviders } from "providers";
export class ManualProvider implements StreamProvider {
@ -23,9 +22,8 @@ export class ManualProvider implements StreamProvider {
};
}
updateStreamInfo(ev: NostrEvent): Promise<void> {
System.BroadcastEvent(ev);
return Promise.resolve();
async updateStreamInfo(system: SystemInterface, ev: NostrEvent): Promise<void> {
await system.BroadcastEvent(ev);
}
topup(): Promise<string> {

View File

@ -6,7 +6,7 @@ import {
StreamProviderStreamInfo,
StreamProviders,
} from ".";
import { EventKind, EventPublisher, NostrEvent } from "@snort/system";
import { EventKind, EventPublisher, NostrEvent, SystemInterface } from "@snort/system";
import { Login, StreamState } from "index";
import { getPublisher } from "login";
import { findTag } from "utils";
@ -53,7 +53,7 @@ export class Nip103StreamProvider implements StreamProvider {
};
}
async updateStreamInfo(ev: NostrEvent): Promise<void> {
async updateStreamInfo(system: SystemInterface, ev: NostrEvent): Promise<void> {
const title = findTag(ev, "title");
const summary = findTag(ev, "summary");
const image = findTag(ev, "image");

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Зап Тревога"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "জ্যাপ অ্যালার্ট"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Alerta de Zap"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "هشدار زپ"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap-hälytys"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Alerte Zap"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Riadó"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "ザップアラート"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Alerta Zap"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Оповещение о запе"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Tahadhari ya Zap"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "Zap Alert"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "打闪提示"
}
}

View File

@ -418,4 +418,3 @@
"defaultMessage": "打閃提示"
}
}

View File

@ -1,9 +1,7 @@
import { NostrEvent, NostrPrefix, TaggedNostrEvent, createNostrLink, encodeTLV } from "@snort/system";
import * as utils from "@noble/curves/abstract/utils";
import { bech32 } from "@scure/base";
import type { Tag, Tags } from "types";
import { NostrEvent, NostrLink, TaggedNostrEvent } from "@snort/system";
import type { Tags } from "types";
import { LIVE_STREAM } from "const";
import { unwrap } from "@snort/shared";
export function toAddress(e: NostrEvent): string {
if (e.kind && e.kind >= 30000 && e.kind <= 40000) {
@ -19,20 +17,6 @@ export function toAddress(e: NostrEvent): string {
return e.id;
}
export function toTag(e: NostrEvent): Tag {
if (e.kind && e.kind >= 30000 && e.kind <= 40000) {
const dTag = findTag(e, "d");
return ["a", `${e.kind}:${e.pubkey}:${dTag}`];
}
if (e.kind === 0 || e.kind === 3) {
return ["p", e.pubkey];
}
return ["e", e.id];
}
export function findTag(e: NostrEvent | undefined, tag: string) {
const maybeTag = e?.tags.find(evTag => {
return evTag[0] === tag;
@ -40,27 +24,6 @@ export function findTag(e: NostrEvent | undefined, tag: string) {
return maybeTag && maybeTag[1];
}
/**
* Convert hex to bech32
*/
export function hexToBech32(hrp: string, hex?: string) {
if (typeof hex !== "string" || hex.length === 0 || hex.length % 2 !== 0) {
return "";
}
try {
if (hrp === NostrPrefix.Note || hrp === NostrPrefix.PrivateKey || hrp === NostrPrefix.PublicKey) {
const buf = utils.hexToBytes(hex);
return bech32.encode(hrp, bech32.toWords(buf));
} else {
return encodeTLV(hrp as NostrPrefix, hex);
}
} catch (e) {
console.warn("Invalid hex", hex, e);
return "";
}
}
export function splitByUrl(str: string) {
const urlRegex =
/((?:http|ftp|https|nostr|web\+nostr|magnet):\/?\/?(?:[\w+?.\w+])+(?:[a-zA-Z0-9~!@#$%^&*()_\-=+\\/?.:;',]*)?(?:[-A-Za-z0-9+&@#/%=~()_|]))/i;
@ -69,12 +32,7 @@ export function splitByUrl(str: string) {
}
export function eventLink(ev: NostrEvent | TaggedNostrEvent) {
if (ev.kind && ev.kind >= 30000 && ev.kind <= 40000) {
const d = findTag(ev, "d") ?? "";
return encodeTLV(NostrPrefix.Address, d, "relays" in ev ? ev.relays : undefined, ev.kind, ev.pubkey);
} else {
return encodeTLV(NostrPrefix.Event, ev.id, "relays" in ev ? ev.relays : undefined);
}
return NostrLink.fromEvent(ev).encode();
}
export function getHost(ev?: NostrEvent) {
@ -110,11 +68,3 @@ export function getEventFromLocationState(state: unknown | undefined | null) {
? (state as NostrEvent)
: undefined;
}
export function eventToLink(ev: NostrEvent) {
if (ev.kind >= 30_000 && ev.kind < 40_000) {
const dTag = unwrap(findTag(ev, "d"));
return createNostrLink(NostrPrefix.Address, dTag, undefined, ev.kind, ev.pubkey);
}
return createNostrLink(NostrPrefix.Event, ev.id, undefined, ev.kind, ev.pubkey);
}

732
yarn.lock
View File

@ -2479,44 +2479,68 @@ __metadata:
languageName: node
linkType: hard
"@snort/shared@npm:^1.0.5":
version: 1.0.5
resolution: "@snort/shared@npm:1.0.5"
"@snort/shared@npm:^1.0.7":
version: 1.0.7
resolution: "@snort/shared@npm:1.0.7"
dependencies:
"@noble/curves": ^1.2.0
"@noble/hashes": ^1.3.2
"@scure/base": ^1.1.2
debug: ^4.3.4
dexie: ^3.2.4
light-bolt11-decoder: ^3.0.0
checksum: 25ada095ecc059cbd0a1ff79d2372484aa4171ec8d697b880ad924a353d54290c5dbc9457ef52aac512bf1984d787a3cfaf35610b4d9bc968fe327da35fd7c1c
checksum: 83b61a945906896a40877dccc5d8c2bcb5a3a5cb49960db1595409fbfd8704f7d297b1350792b82447b328a26db3cb4967f0c662affe0365418376e45010a016
languageName: node
linkType: hard
"@snort/system-react@npm:^1.0.13":
version: 1.0.13
resolution: "@snort/system-react@npm:1.0.13"
dependencies:
"@snort/shared": ^1.0.5
"@snort/system": ^1.0.18
react: ^18.2.0
checksum: 0d3cbc1291faed6cee2c12706932e84fd3c5f8ff91d3f03f92f493fe58846cd7c5691fec3750aa0579f6ae46e0ab57a67c055a417540379c435d91db9887f794
languageName: node
linkType: hard
"@snort/system@npm:^1.0.18":
version: 1.0.18
resolution: "@snort/system@npm:1.0.18"
"@snort/shared@npm:^1.0.8":
version: 1.0.8
resolution: "@snort/shared@npm:1.0.8"
dependencies:
"@noble/curves": ^1.2.0
"@noble/hashes": ^1.3.2
"@scure/base": ^1.1.2
"@snort/shared": ^1.0.5
debug: ^4.3.4
light-bolt11-decoder: ^3.0.0
checksum: d91e4ffbd901931b05fdb953c2478b781fee1917551b51213e8e4c75a263c6fe2b230d908b036ca6d515d46bbe251adbd09792f150d89a8669f680f89d2f0344
languageName: node
linkType: hard
"@snort/system-react@npm:^1.0.19":
version: 1.0.19
resolution: "@snort/system-react@npm:1.0.19"
dependencies:
"@snort/shared": ^1.0.8
"@snort/system": ^1.0.22
react: ^18.2.0
checksum: 317024f1726e70c6ba2d62c40cf60a8ae6e96f6b52961a6491fdf18e10db1f9a97e8c60f196146b083de22b351d938e7f665266f9e2ffdc1198aed52ebbd8fc8
languageName: node
linkType: hard
"@snort/system-web@npm:^1.0.1":
version: 1.0.1
resolution: "@snort/system-web@npm:1.0.1"
dependencies:
"@snort/shared": ^1.0.7
"@snort/system": ^1.0.22
dexie: ^3.2.4
checksum: 5b213a8fd44b0e73193574cf8229798eeb50528f4291741d41b75a8154433cf4500327e29259734a1872cd6fc3cac22411a94eb2b7178d1ce3dbe1a5585bf9c7
languageName: node
linkType: hard
"@snort/system@npm:^1.0.22":
version: 1.0.22
resolution: "@snort/system@npm:1.0.22"
dependencies:
"@noble/curves": ^1.2.0
"@noble/hashes": ^1.3.2
"@scure/base": ^1.1.2
"@snort/shared": ^1.0.7
"@stablelib/xchacha20": ^1.0.1
debug: ^4.3.4
dexie: ^3.2.4
isomorphic-ws: ^5.0.0
uuid: ^9.0.0
checksum: 6539126720e9cf3bee139eaeec96051df5b3ab082c5a1e8b9183a85bb3b51654076826e1ef14e85ecc1ffd5fed4809075756f0d912f5a5d51c37d785922f038f
ws: ^8.14.0
checksum: 4d999aa94b7e07b04e9f18d75cd2b33ca364862a13abc0f2ff80d27f1988867f482c1fcefb5b5b276c049434041aca41e09e842e008c95b9bb6eaeffaaa1f9c8
languageName: node
linkType: hard
@ -2722,15 +2746,6 @@ __metadata:
languageName: node
linkType: hard
"@types/debug@npm:^4.0.0":
version: 4.1.8
resolution: "@types/debug@npm:4.1.8"
dependencies:
"@types/ms": "*"
checksum: a9a9bb40a199e9724aa944e139a7659173a9b274798ea7efbc277cb084bc37d32fc4c00877c3496fac4fed70a23243d284adb75c00b5fdabb38a22154d18e5df
languageName: node
linkType: hard
"@types/eslint-scope@npm:^3.7.3":
version: 3.7.4
resolution: "@types/eslint-scope@npm:3.7.4"
@ -2789,15 +2804,6 @@ __metadata:
languageName: node
linkType: hard
"@types/hast@npm:^2.0.0":
version: 2.3.5
resolution: "@types/hast@npm:2.3.5"
dependencies:
"@types/unist": ^2
checksum: e435e9fbf6afc616ade377d2246a632fb75f4064be4bfd619b67a1ba0d9935d75968a18fbdb66535dfb5e77ef81f4b9b56fd8f35c1cffa34b48ddb0287fec91e
languageName: node
linkType: hard
"@types/hoist-non-react-statics@npm:^3.3.1":
version: 3.3.1
resolution: "@types/hoist-non-react-statics@npm:3.3.1"
@ -2896,15 +2902,6 @@ __metadata:
languageName: node
linkType: hard
"@types/mdast@npm:^3.0.0":
version: 3.0.12
resolution: "@types/mdast@npm:3.0.12"
dependencies:
"@types/unist": ^2
checksum: 83adb8679b9d139f69f63554d120af921e9f1289e9903a2c99e0554a327c8524a6c0beccdc0721e4fdbccc606e81964fecb0d390d53df0f74360938e22f1a469
languageName: node
linkType: hard
"@types/mime@npm:*":
version: 3.0.1
resolution: "@types/mime@npm:3.0.1"
@ -2919,13 +2916,6 @@ __metadata:
languageName: node
linkType: hard
"@types/ms@npm:*":
version: 0.7.31
resolution: "@types/ms@npm:0.7.31"
checksum: daadd354aedde024cce6f5aa873fefe7b71b22cd0e28632a69e8b677aeb48ae8caa1c60e5919bb781df040d116b01cb4316335167a3fc0ef6a63fa3614c0f6da
languageName: node
linkType: hard
"@types/node@npm:*":
version: 20.5.6
resolution: "@types/node@npm:20.5.6"
@ -2940,7 +2930,7 @@ __metadata:
languageName: node
linkType: hard
"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0":
"@types/prop-types@npm:*":
version: 15.7.5
resolution: "@types/prop-types@npm:15.7.5"
checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980
@ -3082,13 +3072,6 @@ __metadata:
languageName: node
linkType: hard
"@types/unist@npm:^2, @types/unist@npm:^2.0.0":
version: 2.0.7
resolution: "@types/unist@npm:2.0.7"
checksum: b97a219554e83431f19a93ff113306bf0512909292815e8f32964e47d041c505af1aaa2a381c23e137c4c0b962fad58d4ce9c5c3256642921a466be43c1fc715
languageName: node
linkType: hard
"@types/webscopeio__react-textarea-autocomplete@npm:^4.7.2":
version: 4.7.2
resolution: "@types/webscopeio__react-textarea-autocomplete@npm:4.7.2"
@ -3848,13 +3831,6 @@ __metadata:
languageName: node
linkType: hard
"bail@npm:^2.0.0":
version: 2.0.2
resolution: "bail@npm:2.0.2"
checksum: aab4e8ccdc8d762bf3fdfce8e706601695620c0c2eda256dd85088dc0be3cfd7ff126f6e99c2bee1f24f5d418414aacf09d7f9702f16d6963df2fa488cda8824
languageName: node
linkType: hard
"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
@ -4099,13 +4075,6 @@ __metadata:
languageName: node
linkType: hard
"character-entities@npm:^2.0.0":
version: 2.0.2
resolution: "character-entities@npm:2.0.2"
checksum: cf1643814023697f725e47328fcec17923b8f1799102a8a79c1514e894815651794a2bffd84bb1b3a4b124b050154e4529ed6e81f7c8068a734aecf07a6d3def
languageName: node
linkType: hard
"chokidar@npm:^3.5.3":
version: 3.5.3
resolution: "chokidar@npm:3.5.3"
@ -4228,13 +4197,6 @@ __metadata:
languageName: node
linkType: hard
"comma-separated-tokens@npm:^2.0.0":
version: 2.0.3
resolution: "comma-separated-tokens@npm:2.0.3"
checksum: e3bf9e0332a5c45f49b90e79bcdb4a7a85f28d6a6f0876a94f1bb9b2bfbdbbb9292aac50e1e742d8c0db1e62a0229a106f57917e2d067fca951d81737651700d
languageName: node
linkType: hard
"commander@npm:^10.0.1":
version: 10.0.1
resolution: "commander@npm:10.0.1"
@ -4633,7 +4595,7 @@ __metadata:
languageName: node
linkType: hard
"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4":
"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4":
version: 4.3.4
resolution: "debug@npm:4.3.4"
dependencies:
@ -4645,15 +4607,6 @@ __metadata:
languageName: node
linkType: hard
"decode-named-character-reference@npm:^1.0.0":
version: 1.0.2
resolution: "decode-named-character-reference@npm:1.0.2"
dependencies:
character-entities: ^2.0.0
checksum: f4c71d3b93105f20076052f9cb1523a22a9c796b8296cd35eef1ca54239c78d182c136a848b83ff8da2071e3ae2b1d300bf29d00650a6d6e675438cc31b11d78
languageName: node
linkType: hard
"deep-equal@npm:^2.0.5":
version: 2.2.2
resolution: "deep-equal@npm:2.2.2"
@ -4741,7 +4694,7 @@ __metadata:
languageName: node
linkType: hard
"dequal@npm:^2.0.0, dequal@npm:^2.0.3":
"dequal@npm:^2.0.3":
version: 2.0.3
resolution: "dequal@npm:2.0.3"
checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90
@ -4783,13 +4736,6 @@ __metadata:
languageName: node
linkType: hard
"diff@npm:^5.0.0":
version: 5.1.0
resolution: "diff@npm:5.1.0"
checksum: c7bf0df7c9bfbe1cf8a678fd1b2137c4fb11be117a67bc18a0e03ae75105e8533dbfb1cda6b46beb3586ef5aed22143ef9d70713977d5fb1f9114e21455fba90
languageName: node
linkType: hard
"dir-glob@npm:^3.0.1":
version: 3.0.1
resolution: "dir-glob@npm:3.0.1"
@ -5432,13 +5378,6 @@ __metadata:
languageName: node
linkType: hard
"extend@npm:^3.0.0":
version: 3.0.2
resolution: "extend@npm:3.0.2"
checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515
languageName: node
linkType: hard
"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
version: 3.1.3
resolution: "fast-deep-equal@npm:3.1.3"
@ -6017,13 +5956,6 @@ __metadata:
languageName: node
linkType: hard
"hast-util-whitespace@npm:^2.0.0":
version: 2.0.1
resolution: "hast-util-whitespace@npm:2.0.1"
checksum: 431be6b2f35472f951615540d7a53f69f39461e5e080c0190268bdeb2be9ab9b1dddfd1f467dd26c1de7e7952df67beb1307b6ee940baf78b24a71b5e0663868
languageName: node
linkType: hard
"he@npm:^1.2.0":
version: 1.2.0
resolution: "he@npm:1.2.0"
@ -6332,13 +6264,6 @@ __metadata:
languageName: node
linkType: hard
"inline-style-parser@npm:0.1.1":
version: 0.1.1
resolution: "inline-style-parser@npm:0.1.1"
checksum: 5d545056a3e1f2bf864c928a886a0e1656a3517127d36917b973de581bd54adc91b4bf1febcb0da054f204b4934763f1a4e09308b4d55002327cf1d48ac5d966
languageName: node
linkType: hard
"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5":
version: 1.0.5
resolution: "internal-slot@npm:1.0.5"
@ -6448,13 +6373,6 @@ __metadata:
languageName: node
linkType: hard
"is-buffer@npm:^2.0.0":
version: 2.0.5
resolution: "is-buffer@npm:2.0.5"
checksum: 764c9ad8b523a9f5a32af29bdf772b08eb48c04d2ad0a7240916ac2688c983bf5f8504bf25b35e66240edeb9d9085461f9b5dae1f3d2861c6b06a65fe983de42
languageName: node
linkType: hard
"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7":
version: 1.2.7
resolution: "is-callable@npm:1.2.7"
@ -6577,13 +6495,6 @@ __metadata:
languageName: node
linkType: hard
"is-plain-obj@npm:^4.0.0":
version: 4.1.0
resolution: "is-plain-obj@npm:4.1.0"
checksum: 6dc45da70d04a81f35c9310971e78a6a3c7a63547ef782e3a07ee3674695081b6ca4e977fbb8efc48dae3375e0b34558d2bcd722aec9bddfa2d7db5b041be8ce
languageName: node
linkType: hard
"is-plain-object@npm:^2.0.4":
version: 2.0.4
resolution: "is-plain-object@npm:2.0.4"
@ -6723,6 +6634,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: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
languageName: node
linkType: hard
"jackspeak@npm:^2.0.3":
version: 2.3.0
resolution: "jackspeak@npm:2.3.0"
@ -6985,13 +6905,6 @@ __metadata:
languageName: node
linkType: hard
"kleur@npm:^4.0.3":
version: 4.1.5
resolution: "kleur@npm:4.1.5"
checksum: 1dc476e32741acf0b1b5b0627ffd0d722e342c1b0da14de3e8ae97821327ca08f9fb944542fb3c126d90ac5f27f9d804edbe7c585bf7d12ef495d115e0f22c12
languageName: node
linkType: hard
"launch-editor@npm:^2.6.0":
version: 2.6.0
resolution: "launch-editor@npm:2.6.0"
@ -7242,59 +7155,12 @@ __metadata:
languageName: node
linkType: hard
"mdast-util-definitions@npm:^5.0.0":
version: 5.1.2
resolution: "mdast-util-definitions@npm:5.1.2"
dependencies:
"@types/mdast": ^3.0.0
"@types/unist": ^2.0.0
unist-util-visit: ^4.0.0
checksum: 2544daccab744ea1ede76045c2577ae4f1cc1b9eb1ea51ab273fe1dca8db5a8d6f50f87759c0ce6484975914b144b7f40316f805cb9c86223a78db8de0b77bae
languageName: node
linkType: hard
"mdast-util-from-markdown@npm:^1.0.0":
version: 1.3.1
resolution: "mdast-util-from-markdown@npm:1.3.1"
dependencies:
"@types/mdast": ^3.0.0
"@types/unist": ^2.0.0
decode-named-character-reference: ^1.0.0
mdast-util-to-string: ^3.1.0
micromark: ^3.0.0
micromark-util-decode-numeric-character-reference: ^1.0.0
micromark-util-decode-string: ^1.0.0
micromark-util-normalize-identifier: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
unist-util-stringify-position: ^3.0.0
uvu: ^0.5.0
checksum: c2fac225167e248d394332a4ea39596e04cbde07d8cdb3889e91e48972c4c3462a02b39fda3855345d90231eb17a90ac6e082fb4f012a77c1d0ddfb9c7446940
languageName: node
linkType: hard
"mdast-util-to-hast@npm:^12.1.0":
version: 12.3.0
resolution: "mdast-util-to-hast@npm:12.3.0"
dependencies:
"@types/hast": ^2.0.0
"@types/mdast": ^3.0.0
mdast-util-definitions: ^5.0.0
micromark-util-sanitize-uri: ^1.1.0
trim-lines: ^3.0.0
unist-util-generated: ^2.0.0
unist-util-position: ^4.0.0
unist-util-visit: ^4.0.0
checksum: ea40c9f07dd0b731754434e81c913590c611b1fd753fa02550a1492aadfc30fb3adecaf62345ebb03cea2ddd250c15ab6e578fffde69c19955c9b87b10f2a9bb
languageName: node
linkType: hard
"mdast-util-to-string@npm:^3.1.0":
version: 3.2.0
resolution: "mdast-util-to-string@npm:3.2.0"
dependencies:
"@types/mdast": ^3.0.0
checksum: dc40b544d54339878ae2c9f2b3198c029e1e07291d2126bd00ca28272ee6616d0d2194eb1c9828a7c34d412a79a7e73b26512a734698d891c710a1e73db1e848
"marked@npm:^9.1.2":
version: 9.1.2
resolution: "marked@npm:9.1.2"
bin:
marked: bin/marked.js
checksum: 8dd1b9e268f149d770397b5299e73dc6b5ae915f867acfaa166603eb5b137cfadaa40406048f424371729036abdf3b0bb629223520571534ec32e27746a798d2
languageName: node
linkType: hard
@ -7356,242 +7222,6 @@ __metadata:
languageName: node
linkType: hard
"micromark-core-commonmark@npm:^1.0.1":
version: 1.1.0
resolution: "micromark-core-commonmark@npm:1.1.0"
dependencies:
decode-named-character-reference: ^1.0.0
micromark-factory-destination: ^1.0.0
micromark-factory-label: ^1.0.0
micromark-factory-space: ^1.0.0
micromark-factory-title: ^1.0.0
micromark-factory-whitespace: ^1.0.0
micromark-util-character: ^1.0.0
micromark-util-chunked: ^1.0.0
micromark-util-classify-character: ^1.0.0
micromark-util-html-tag-name: ^1.0.0
micromark-util-normalize-identifier: ^1.0.0
micromark-util-resolve-all: ^1.0.0
micromark-util-subtokenize: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.1
uvu: ^0.5.0
checksum: c6dfedc95889cc73411cb222fc2330b9eda6d849c09c9fd9eb3cd3398af246167e9d3cdb0ae3ce9ae59dd34a14624c8330e380255d41279ad7350cf6c6be6c5b
languageName: node
linkType: hard
"micromark-factory-destination@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-destination@npm:1.1.0"
dependencies:
micromark-util-character: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
checksum: 9e2b5fb5fedbf622b687e20d51eb3d56ae90c0e7ecc19b37bd5285ec392c1e56f6e21aa7cfcb3c01eda88df88fe528f3acb91a5f57d7f4cba310bc3cd7f824fa
languageName: node
linkType: hard
"micromark-factory-label@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-label@npm:1.1.0"
dependencies:
micromark-util-character: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
uvu: ^0.5.0
checksum: fcda48f1287d9b148c562c627418a2ab759cdeae9c8e017910a0cba94bb759a96611e1fc6df33182e97d28fbf191475237298983bb89ef07d5b02464b1ad28d5
languageName: node
linkType: hard
"micromark-factory-space@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-space@npm:1.1.0"
dependencies:
micromark-util-character: ^1.0.0
micromark-util-types: ^1.0.0
checksum: b58435076b998a7e244259a4694eb83c78915581206b6e7fc07b34c6abd36a1726ade63df8972fbf6c8fa38eecb9074f4e17be8d53f942e3b3d23d1a0ecaa941
languageName: node
linkType: hard
"micromark-factory-title@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-title@npm:1.1.0"
dependencies:
micromark-factory-space: ^1.0.0
micromark-util-character: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
checksum: 4432d3dbc828c81f483c5901b0c6591a85d65a9e33f7d96ba7c3ae821617a0b3237ff5faf53a9152d00aaf9afb3a9f185b205590f40ed754f1d9232e0e9157b1
languageName: node
linkType: hard
"micromark-factory-whitespace@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-factory-whitespace@npm:1.1.0"
dependencies:
micromark-factory-space: ^1.0.0
micromark-util-character: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
checksum: ef0fa682c7d593d85a514ee329809dee27d10bc2a2b65217d8ef81173e33b8e83c549049764b1ad851adfe0a204dec5450d9d20a4ca8598f6c94533a73f73fcd
languageName: node
linkType: hard
"micromark-util-character@npm:^1.0.0":
version: 1.2.0
resolution: "micromark-util-character@npm:1.2.0"
dependencies:
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
checksum: 089e79162a19b4a28731736246579ab7e9482ac93cd681c2bfca9983dcff659212ef158a66a5957e9d4b1dba957d1b87b565d85418a5b009f0294f1f07f2aaac
languageName: node
linkType: hard
"micromark-util-chunked@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-chunked@npm:1.1.0"
dependencies:
micromark-util-symbol: ^1.0.0
checksum: c435bde9110cb595e3c61b7f54c2dc28ee03e6a57fa0fc1e67e498ad8bac61ee5a7457a2b6a73022ddc585676ede4b912d28dcf57eb3bd6951e54015e14dc20b
languageName: node
linkType: hard
"micromark-util-classify-character@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-classify-character@npm:1.1.0"
dependencies:
micromark-util-character: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
checksum: 8499cb0bb1f7fb946f5896285fcca65cd742f66cd3e79ba7744792bd413ec46834f932a286de650349914d02e822946df3b55d03e6a8e1d245d1ddbd5102e5b0
languageName: node
linkType: hard
"micromark-util-combine-extensions@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-combine-extensions@npm:1.1.0"
dependencies:
micromark-util-chunked: ^1.0.0
micromark-util-types: ^1.0.0
checksum: ee78464f5d4b61ccb437850cd2d7da4d690b260bca4ca7a79c4bb70291b84f83988159e373b167181b6716cb197e309bc6e6c96a68cc3ba9d50c13652774aba9
languageName: node
linkType: hard
"micromark-util-decode-numeric-character-reference@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-decode-numeric-character-reference@npm:1.1.0"
dependencies:
micromark-util-symbol: ^1.0.0
checksum: 4733fe75146e37611243f055fc6847137b66f0cde74d080e33bd26d0408c1d6f44cabc984063eee5968b133cb46855e729d555b9ff8d744652262b7b51feec73
languageName: node
linkType: hard
"micromark-util-decode-string@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-decode-string@npm:1.1.0"
dependencies:
decode-named-character-reference: ^1.0.0
micromark-util-character: ^1.0.0
micromark-util-decode-numeric-character-reference: ^1.0.0
micromark-util-symbol: ^1.0.0
checksum: f1625155db452f15aa472918499689ba086b9c49d1322a08b22bfbcabe918c61b230a3002c8bc3ea9b1f52ca7a9bb1c3dd43ccb548c7f5f8b16c24a1ae77a813
languageName: node
linkType: hard
"micromark-util-encode@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-encode@npm:1.1.0"
checksum: 4ef29d02b12336918cea6782fa87c8c578c67463925221d4e42183a706bde07f4b8b5f9a5e1c7ce8c73bb5a98b261acd3238fecd152e6dd1cdfa2d1ae11b60a0
languageName: node
linkType: hard
"micromark-util-html-tag-name@npm:^1.0.0":
version: 1.2.0
resolution: "micromark-util-html-tag-name@npm:1.2.0"
checksum: ccf0fa99b5c58676dc5192c74665a3bfd1b536fafaf94723bd7f31f96979d589992df6fcf2862eba290ef18e6a8efb30ec8e1e910d9f3fc74f208871e9f84750
languageName: node
linkType: hard
"micromark-util-normalize-identifier@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-normalize-identifier@npm:1.1.0"
dependencies:
micromark-util-symbol: ^1.0.0
checksum: 8655bea41ffa4333e03fc22462cb42d631bbef9c3c07b625fd852b7eb442a110f9d2e5902a42e65188d85498279569502bf92f3434a1180fc06f7c37edfbaee2
languageName: node
linkType: hard
"micromark-util-resolve-all@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-resolve-all@npm:1.1.0"
dependencies:
micromark-util-types: ^1.0.0
checksum: 1ce6c0237cd3ca061e76fae6602cf95014e764a91be1b9f10d36cb0f21ca88f9a07de8d49ab8101efd0b140a4fbfda6a1efb72027ab3f4d5b54c9543271dc52c
languageName: node
linkType: hard
"micromark-util-sanitize-uri@npm:^1.0.0, micromark-util-sanitize-uri@npm:^1.1.0":
version: 1.2.0
resolution: "micromark-util-sanitize-uri@npm:1.2.0"
dependencies:
micromark-util-character: ^1.0.0
micromark-util-encode: ^1.0.0
micromark-util-symbol: ^1.0.0
checksum: 6663f365c4fe3961d622a580f4a61e34867450697f6806f027f21cf63c92989494895fcebe2345d52e249fe58a35be56e223a9776d084c9287818b40c779acc1
languageName: node
linkType: hard
"micromark-util-subtokenize@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-subtokenize@npm:1.1.0"
dependencies:
micromark-util-chunked: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.0
uvu: ^0.5.0
checksum: 4a9d780c4d62910e196ea4fd886dc4079d8e424e5d625c0820016da0ed399a281daff39c50f9288045cc4bcd90ab47647e5396aba500f0853105d70dc8b1fc45
languageName: node
linkType: hard
"micromark-util-symbol@npm:^1.0.0":
version: 1.1.0
resolution: "micromark-util-symbol@npm:1.1.0"
checksum: 02414a753b79f67ff3276b517eeac87913aea6c028f3e668a19ea0fc09d98aea9f93d6222a76ca783d20299af9e4b8e7c797fe516b766185dcc6e93290f11f88
languageName: node
linkType: hard
"micromark-util-types@npm:^1.0.0, micromark-util-types@npm:^1.0.1":
version: 1.1.0
resolution: "micromark-util-types@npm:1.1.0"
checksum: b0ef2b4b9589f15aec2666690477a6a185536927ceb7aa55a0f46475852e012d75a1ab945187e5c7841969a842892164b15d58ff8316b8e0d6cc920cabd5ede7
languageName: node
linkType: hard
"micromark@npm:^3.0.0":
version: 3.2.0
resolution: "micromark@npm:3.2.0"
dependencies:
"@types/debug": ^4.0.0
debug: ^4.0.0
decode-named-character-reference: ^1.0.0
micromark-core-commonmark: ^1.0.1
micromark-factory-space: ^1.0.0
micromark-util-character: ^1.0.0
micromark-util-chunked: ^1.0.0
micromark-util-combine-extensions: ^1.0.0
micromark-util-decode-numeric-character-reference: ^1.0.0
micromark-util-encode: ^1.0.0
micromark-util-normalize-identifier: ^1.0.0
micromark-util-resolve-all: ^1.0.0
micromark-util-sanitize-uri: ^1.0.0
micromark-util-subtokenize: ^1.0.0
micromark-util-symbol: ^1.0.0
micromark-util-types: ^1.0.1
uvu: ^0.5.0
checksum: 56c15851ad3eb8301aede65603473443e50c92a54849cac1dadd57e4ec33ab03a0a77f3df03de47133e6e8f695dae83b759b514586193269e98c0bf319ecd5e4
languageName: node
linkType: hard
"micromatch@npm:^4.0.0, micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5":
version: 4.0.5
resolution: "micromatch@npm:4.0.5"
@ -7786,13 +7416,6 @@ __metadata:
languageName: node
linkType: hard
"mri@npm:^1.1.0":
version: 1.2.0
resolution: "mri@npm:1.2.0"
checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85
languageName: node
linkType: hard
"mrmime@npm:^1.0.0":
version: 1.0.1
resolution: "mrmime@npm:1.0.1"
@ -8742,7 +8365,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.0.0, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@ -8753,13 +8376,6 @@ __metadata:
languageName: node
linkType: hard
"property-information@npm:^6.0.0":
version: 6.2.0
resolution: "property-information@npm:6.2.0"
checksum: 23afce07ba821cbe7d926e63cdd680991961c82be4bbb6c0b17c47f48894359c1be6e51cd74485fc10a9d3fd361b475388e1e39311ed2b53127718f72aab1955
languageName: node
linkType: hard
"proxy-addr@npm:~2.0.7":
version: 2.0.7
resolution: "proxy-addr@npm:2.0.7"
@ -8969,32 +8585,6 @@ __metadata:
languageName: node
linkType: hard
"react-markdown@npm:^8.0.7":
version: 8.0.7
resolution: "react-markdown@npm:8.0.7"
dependencies:
"@types/hast": ^2.0.0
"@types/prop-types": ^15.0.0
"@types/unist": ^2.0.0
comma-separated-tokens: ^2.0.0
hast-util-whitespace: ^2.0.0
prop-types: ^15.0.0
property-information: ^6.0.0
react-is: ^18.0.0
remark-parse: ^10.0.0
remark-rehype: ^10.0.0
space-separated-tokens: ^2.0.0
style-to-object: ^0.4.0
unified: ^10.0.0
unist-util-visit: ^4.0.0
vfile: ^5.0.0
peerDependencies:
"@types/react": ">=16"
react: ">=16"
checksum: 0f3e570975134a3382c3fe5189e04e742ae154941463bdfaab2293319da1f1585cb9b75b6f07d99f514c4d728d69cc1af3c96ab37df90003b3bcc210dd0001ba
languageName: node
linkType: hard
"react-remove-scroll-bar@npm:^2.3.3":
version: 2.3.4
resolution: "react-remove-scroll-bar@npm:2.3.4"
@ -9247,29 +8837,6 @@ __metadata:
languageName: node
linkType: hard
"remark-parse@npm:^10.0.0":
version: 10.0.2
resolution: "remark-parse@npm:10.0.2"
dependencies:
"@types/mdast": ^3.0.0
mdast-util-from-markdown: ^1.0.0
unified: ^10.0.0
checksum: 5041b4b44725f377e69986e02f8f072ae2222db5e7d3b6c80829756b842e811343ffc2069cae1f958a96bfa36104ab91a57d7d7e2f0cef521e210ab8c614d5c7
languageName: node
linkType: hard
"remark-rehype@npm:^10.0.0":
version: 10.1.0
resolution: "remark-rehype@npm:10.1.0"
dependencies:
"@types/hast": ^2.0.0
"@types/mdast": ^3.0.0
mdast-util-to-hast: ^12.1.0
unified: ^10.0.0
checksum: b9ac8acff3383b204dfdc2599d0bdf86e6ca7e837033209584af2e6aaa6a9013e519a379afa3201299798cab7298c8f4b388de118c312c67234c133318aec084
languageName: node
linkType: hard
"renderkid@npm:^3.0.0":
version: 3.0.0
resolution: "renderkid@npm:3.0.0"
@ -9415,15 +8982,6 @@ __metadata:
languageName: node
linkType: hard
"sade@npm:^1.7.3":
version: 1.8.1
resolution: "sade@npm:1.8.1"
dependencies:
mri: ^1.1.0
checksum: 0756e5b04c51ccdc8221ebffd1548d0ce5a783a44a0fa9017a026659b97d632913e78f7dca59f2496aa996a0be0b0c322afd87ca72ccd909406f49dbffa0f45d
languageName: node
linkType: hard
"safe-array-concat@npm:^1.0.0":
version: 1.0.0
resolution: "safe-array-concat@npm:1.0.0"
@ -9838,13 +9396,6 @@ __metadata:
languageName: node
linkType: hard
"space-separated-tokens@npm:^2.0.0":
version: 2.0.2
resolution: "space-separated-tokens@npm:2.0.2"
checksum: 202e97d7ca1ba0758a0aa4fe226ff98142073bcceeff2da3aad037968878552c3bbce3b3231970025375bbba5aee00c5b8206eda408da837ab2dc9c0f26be990
languageName: node
linkType: hard
"spdy-transport@npm:^3.0.0":
version: 3.0.0
resolution: "spdy-transport@npm:3.0.0"
@ -9935,9 +9486,10 @@ __metadata:
"@radix-ui/react-toggle": ^1.0.3
"@react-hook/resize-observer": ^1.2.6
"@scure/base": ^1.1.1
"@snort/shared": ^1.0.5
"@snort/system": ^1.0.18
"@snort/system-react": ^1.0.13
"@snort/shared": ^1.0.8
"@snort/system": ^1.0.22
"@snort/system-react": ^1.0.19
"@snort/system-web": ^1.0.1
"@szhsin/react-menu": ^4.0.2
"@testing-library/dom": ^9.3.1
"@testing-library/jest-dom": ^5.14.1
@ -9967,6 +9519,7 @@ __metadata:
html-webpack-plugin: ^5.5.1
lodash: ^4.17.21
lodash.uniqby: ^4.7.0
marked: ^9.1.2
mini-css-extract-plugin: ^2.7.5
moment: ^2.29.4
prettier: ^2.8.8
@ -9980,7 +9533,6 @@ __metadata:
react-helmet: ^6.1.0
react-intersection-observer: ^9.5.1
react-intl: ^6.4.4
react-markdown: ^8.0.7
react-router-dom: ^6.13.0
react-tag-input-component: ^2.0.2
semantic-sdp: ^3.26.3
@ -10151,15 +9703,6 @@ __metadata:
languageName: node
linkType: hard
"style-to-object@npm:^0.4.0":
version: 0.4.2
resolution: "style-to-object@npm:0.4.2"
dependencies:
inline-style-parser: 0.1.1
checksum: 314a80bcfadde41c2b9c8d717a4b1f2220954561040c2c7740496715da5cb95f99920a8eeefe2d4a862149875f352a12eda9bbef5816d7e0a71910da00d1521f
languageName: node
linkType: hard
"stylehacks@npm:^6.0.0":
version: 6.0.0
resolution: "stylehacks@npm:6.0.0"
@ -10358,20 +9901,6 @@ __metadata:
languageName: node
linkType: hard
"trim-lines@npm:^3.0.0":
version: 3.0.1
resolution: "trim-lines@npm:3.0.1"
checksum: e241da104682a0e0d807222cc1496b92e716af4db7a002f4aeff33ae6a0024fef93165d49eab11aa07c71e1347c42d46563f91dfaa4d3fb945aa535cdead53ed
languageName: node
linkType: hard
"trough@npm:^2.0.0":
version: 2.1.0
resolution: "trough@npm:2.1.0"
checksum: a577bb561c2b401cc0e1d9e188fcfcdf63b09b151ff56a668da12197fe97cac15e3d77d5b51f426ccfd94255744a9118e9e9935afe81a3644fa1be9783c82886
languageName: node
linkType: hard
"ts-api-utils@npm:^1.0.1":
version: 1.0.2
resolution: "ts-api-utils@npm:1.0.2"
@ -10553,21 +10082,6 @@ __metadata:
languageName: node
linkType: hard
"unified@npm:^10.0.0":
version: 10.1.2
resolution: "unified@npm:10.1.2"
dependencies:
"@types/unist": ^2.0.0
bail: ^2.0.0
extend: ^3.0.0
is-buffer: ^2.0.0
is-plain-obj: ^4.0.0
trough: ^2.0.0
vfile: ^5.0.0
checksum: 053e7c65ede644607f87bd625a299e4b709869d2f76ec8138569e6e886903b6988b21cd9699e471eda42bee189527be0a9dac05936f1d069a5e65d0125d5d756
languageName: node
linkType: hard
"unique-filename@npm:^3.0.0":
version: 3.0.0
resolution: "unique-filename@npm:3.0.0"
@ -10595,61 +10109,6 @@ __metadata:
languageName: node
linkType: hard
"unist-util-generated@npm:^2.0.0":
version: 2.0.1
resolution: "unist-util-generated@npm:2.0.1"
checksum: 6221ad0571dcc9c8964d6b054f39ef6571ed59cc0ce3e88ae97ea1c70afe76b46412a5ffaa91f96814644ac8477e23fb1b477d71f8d70e625728c5258f5c0d99
languageName: node
linkType: hard
"unist-util-is@npm:^5.0.0":
version: 5.2.1
resolution: "unist-util-is@npm:5.2.1"
dependencies:
"@types/unist": ^2.0.0
checksum: ae76fdc3d35352cd92f1bedc3a0d407c3b9c42599a52ab9141fe89bdd786b51f0ec5a2ab68b93fb532e239457cae62f7e39eaa80229e1cb94875da2eafcbe5c4
languageName: node
linkType: hard
"unist-util-position@npm:^4.0.0":
version: 4.0.4
resolution: "unist-util-position@npm:4.0.4"
dependencies:
"@types/unist": ^2.0.0
checksum: e7487b6cec9365299695e3379ded270a1717074fa11fd2407c9b934fb08db6fe1d9077ddeaf877ecf1813665f8ccded5171693d3d9a7a01a125ec5cdd5e88691
languageName: node
linkType: hard
"unist-util-stringify-position@npm:^3.0.0":
version: 3.0.3
resolution: "unist-util-stringify-position@npm:3.0.3"
dependencies:
"@types/unist": ^2.0.0
checksum: dbd66c15183607ca942a2b1b7a9f6a5996f91c0d30cf8966fb88955a02349d9eefd3974e9010ee67e71175d784c5a9fea915b0aa0b0df99dcb921b95c4c9e124
languageName: node
linkType: hard
"unist-util-visit-parents@npm:^5.1.1":
version: 5.1.3
resolution: "unist-util-visit-parents@npm:5.1.3"
dependencies:
"@types/unist": ^2.0.0
unist-util-is: ^5.0.0
checksum: 8ecada5978994f846b64658cf13b4092cd78dea39e1ba2f5090a5de842ba4852712c02351a8ae95250c64f864635e7b02aedf3b4a093552bb30cf1bd160efbaa
languageName: node
linkType: hard
"unist-util-visit@npm:^4.0.0":
version: 4.1.2
resolution: "unist-util-visit@npm:4.1.2"
dependencies:
"@types/unist": ^2.0.0
unist-util-is: ^5.0.0
unist-util-visit-parents: ^5.1.1
checksum: 95a34e3f7b5b2d4b68fd722b6229972099eb97b6df18913eda44a5c11df8b1e27efe7206dd7b88c4ed244a48c474a5b2e2629ab79558ff9eb936840295549cee
languageName: node
linkType: hard
"universalify@npm:^2.0.0":
version: 2.0.0
resolution: "universalify@npm:2.0.0"
@ -10783,20 +10242,6 @@ __metadata:
languageName: node
linkType: hard
"uvu@npm:^0.5.0":
version: 0.5.6
resolution: "uvu@npm:0.5.6"
dependencies:
dequal: ^2.0.0
diff: ^5.0.0
kleur: ^4.0.3
sade: ^1.7.3
bin:
uvu: bin.js
checksum: 09460a37975627de9fcad396e5078fb844d01aaf64a6399ebfcfd9e55f1c2037539b47611e8631f89be07656962af0cf48c334993db82b9ae9c3d25ce3862168
languageName: node
linkType: hard
"vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"
@ -10804,28 +10249,6 @@ __metadata:
languageName: node
linkType: hard
"vfile-message@npm:^3.0.0":
version: 3.1.4
resolution: "vfile-message@npm:3.1.4"
dependencies:
"@types/unist": ^2.0.0
unist-util-stringify-position: ^3.0.0
checksum: d0ee7da1973ad76513c274e7912adbed4d08d180eaa34e6bd40bc82459f4b7bc50fcaff41556135e3339995575eac5f6f709aba9332b80f775618ea4880a1367
languageName: node
linkType: hard
"vfile@npm:^5.0.0":
version: 5.3.7
resolution: "vfile@npm:5.3.7"
dependencies:
"@types/unist": ^2.0.0
is-buffer: ^2.0.0
unist-util-stringify-position: ^3.0.0
vfile-message: ^3.0.0
checksum: 642cce703afc186dbe7cabf698dc954c70146e853491086f5da39e1ce850676fc96b169fcf7898aa3ff245e9313aeec40da93acd1e1fcc0c146dc4f6308b4ef9
languageName: node
linkType: hard
"watchpack@npm:^2.4.0":
version: 2.4.0
resolution: "watchpack@npm:2.4.0"
@ -11404,6 +10827,21 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:^8.14.0":
version: 8.14.2
resolution: "ws@npm:8.14.2"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ">=5.0.2"
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b
languageName: node
linkType: hard
"yallist@npm:^3.0.2":
version: 3.1.1
resolution: "yallist@npm:3.1.1"