From 80a4b5d8e6ce59bd52b531d1f553d1b58546f056 Mon Sep 17 00:00:00 2001 From: kieran Date: Mon, 22 Apr 2024 14:38:14 +0100 Subject: [PATCH] feat: UserState --- packages/app/.eslintrc.cjs | 41 - packages/app/eslint.config.mjs | 44 + packages/app/package.json | 2 + .../src/Components/Embed/MixCloudEmbed.tsx | 4 +- .../app/src/Components/Embed/PubkeyList.tsx | 13 +- .../Components/Event/Create/NoteCreator.tsx | 16 +- .../Components/Event/Create/OkResponseRow.tsx | 9 +- .../app/src/Components/Event/HiddenNote.tsx | 4 +- .../Components/Event/Note/NoteContextMenu.tsx | 30 +- .../Event/Note/NoteFooter/FooterZapButton.tsx | 17 +- .../Event/Note/NoteFooter/NoteFooter.tsx | 10 +- .../Event/Note/NoteFooter/RepostButton.tsx | 9 +- .../src/Components/Event/Note/NoteHeader.tsx | 24 +- .../src/Components/Event/Note/NoteText.tsx | 6 +- packages/app/src/Components/Event/Poll.tsx | 25 +- .../app/src/Components/Event/RevealMedia.tsx | 11 +- .../src/Components/Event/Thread/Thread.tsx | 2 - .../app/src/Components/Feed/RootTabItems.tsx | 5 +- packages/app/src/Components/Feed/RootTabs.tsx | 18 +- .../src/Components/Feed/TimelineFollows.tsx | 12 +- .../app/src/Components/Feed/UsersFeed.tsx | 4 +- .../src/Components/IntlProvider/useLocale.tsx | 4 +- .../src/Components/PinPrompt/PinPrompt.tsx | 10 +- packages/app/src/Components/ReBroadcaster.tsx | 10 +- packages/app/src/Components/Relay/Relay.tsx | 35 +- .../app/src/Components/SuggestedProfiles.tsx | 6 +- .../src/Components/Trending/TrendingPosts.tsx | 2 +- .../app/src/Components/User/BlockButton.tsx | 25 - .../app/src/Components/User/BlockList.tsx | 15 - .../app/src/Components/User/MutedList.tsx | 33 +- .../src/Components/ZapModal/ZapModalInput.tsx | 7 +- packages/app/src/Feed/ArticlesFeed.ts | 6 +- packages/app/src/Feed/FollowsFeed.ts | 6 +- packages/app/src/Feed/LoginFeed.ts | 177 +- packages/app/src/Feed/ThreadFeed.ts | 23 +- packages/app/src/Feed/TimelineFeed.ts | 10 +- packages/app/src/Hooks/useFollowControls.ts | 62 +- packages/app/src/Hooks/useImgProxy.ts | 6 +- packages/app/src/Hooks/useLists.tsx | 8 - packages/app/src/Hooks/useLoginRelays.tsx | 4 +- packages/app/src/Hooks/useModeration.tsx | 84 +- packages/app/src/Hooks/usePreferences.ts | 28 +- packages/app/src/Hooks/useProfileSearch.tsx | 15 +- packages/app/src/Hooks/useRelays.tsx | 6 + packages/app/src/Hooks/useTheme.tsx | 12 +- packages/app/src/Pages/Deck/DeckLayout.tsx | 5 +- packages/app/src/Pages/HashTagsPage.tsx | 40 +- packages/app/src/Pages/Layout/Header.tsx | 14 +- packages/app/src/Pages/Layout/index.tsx | 5 +- .../app/src/Pages/NetworkGraph/Avatar.tsx | 2 +- .../Notifications/getNotificationContext.tsx | 11 +- .../app/src/Pages/Profile/ProfileDetails.tsx | 8 +- .../app/src/Pages/Profile/ProfilePage.tsx | 25 +- .../app/src/Pages/Profile/ProfileTabType.tsx | 1 - packages/app/src/Pages/Root/DefaultTab.tsx | 9 +- packages/app/src/Pages/Root/ForYouTab.tsx | 28 +- packages/app/src/Pages/Root/NotesTab.tsx | 12 +- packages/app/src/Pages/TopicsPage.tsx | 19 +- .../src/Pages/ZapPool/ZapPoolPageInner.tsx | 20 +- .../app/src/Pages/ZapPool/ZapPoolTarget.tsx | 5 +- .../app/src/Pages/settings/Moderation.tsx | 11 +- .../app/src/Pages/settings/Preferences.tsx | 4 +- packages/app/src/Pages/settings/RelayInfo.tsx | 11 +- packages/app/src/Pages/settings/Relays.tsx | 69 +- .../Pages/settings/tools/prune-follows.tsx | 9 +- .../src/Pages/settings/tools/sync-account.tsx | 4 +- packages/app/src/Utils/Login/Functions.ts | 91 +- packages/app/src/Utils/Login/LoginSession.ts | 45 +- .../app/src/Utils/Login/MultiAccountStore.ts | 124 +- packages/app/src/Utils/Login/Preferences.ts | 6 + packages/app/src/Utils/Thread/ChainKey.tsx | 14 +- .../src/Utils/Thread/ThreadContextWrapper.tsx | 10 +- packages/app/src/Utils/Upload/index.ts | 4 +- packages/app/src/Utils/index.ts | 11 +- packages/app/src/chat/index.ts | 8 +- packages/app/src/index.tsx | 12 +- packages/app/src/service-worker.ts | 10 +- packages/shared/src/utils.ts | 2 +- packages/system/src/connection-pool.ts | 5 +- packages/system/src/connection.ts | 130 +- packages/system/src/event-builder.ts | 6 +- packages/system/src/event-ext.ts | 15 +- packages/system/src/event-publisher.ts | 39 +- packages/system/src/impl/nip10.ts | 73 + .../system/src/{zaps.ts => impl/nip57.ts} | 14 +- packages/system/src/index.ts | 7 +- packages/system/src/nostr-link.ts | 86 +- packages/system/src/note-collection.ts | 3 +- packages/system/src/outbox/index.ts | 21 +- packages/system/src/outbox/outbox-model.ts | 10 + packages/system/src/query-manager.ts | 31 +- packages/system/src/query.ts | 8 +- packages/system/src/relay-info.ts | 1 + packages/system/src/request-builder.ts | 15 +- packages/system/src/request-router.ts | 10 + packages/system/src/signer.ts | 4 +- packages/system/src/sync/diff-sync.ts | 174 +- packages/system/src/sync/index.ts | 4 - .../system/src/sync/json-in-event-sync.ts | 16 +- packages/system/src/sync/safe-sync.ts | 65 +- packages/system/src/user-state.ts | 433 +++ packages/system/tests/Query.test.ts | 3 - yarn.lock | 2622 ++++++++++++++++- 103 files changed, 4179 insertions(+), 1165 deletions(-) delete mode 100644 packages/app/.eslintrc.cjs create mode 100644 packages/app/eslint.config.mjs delete mode 100644 packages/app/src/Components/User/BlockButton.tsx delete mode 100644 packages/app/src/Components/User/BlockList.tsx create mode 100644 packages/app/src/Hooks/useRelays.tsx create mode 100644 packages/system/src/impl/nip10.ts rename packages/system/src/{zaps.ts => impl/nip57.ts} (90%) create mode 100644 packages/system/src/user-state.ts diff --git a/packages/app/.eslintrc.cjs b/packages/app/.eslintrc.cjs deleted file mode 100644 index 3fc75e48..00000000 --- a/packages/app/.eslintrc.cjs +++ /dev/null @@ -1,41 +0,0 @@ -module.exports = { - extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - ], - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint", "formatjs", "react-refresh", "simple-import-sort"], - rules: { - "formatjs/enforce-id": [ - "error", - { - idInterpolationPattern: "[sha512:contenthash:base64:6]", - }, - ], - "react/react-in-jsx-scope": "off", - "react-hooks/exhaustive-deps": "off", - "react-refresh/only-export-components": "error", - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "@typescript-eslint/no-unused-vars": "error", - "max-lines": ["warn", { max: 300, skipBlankLines: true, skipComments: true }], - }, - overrides: [ - { - files: ["*.tsx"], - rules: { - "max-lines": ["warn", { max: 200, skipBlankLines: true, skipComments: true }], - }, - }, - ], - root: true, - ignorePatterns: ["build/", "*.test.ts", "*.js"], - env: { - browser: true, - worker: true, - commonjs: true, - node: false, - }, -}; diff --git a/packages/app/eslint.config.mjs b/packages/app/eslint.config.mjs new file mode 100644 index 00000000..23fa161c --- /dev/null +++ b/packages/app/eslint.config.mjs @@ -0,0 +1,44 @@ +/* eslint-disable import/no-anonymous-default-export */ +export default [ + { + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + ], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "formatjs", "react-refresh", "simple-import-sort"], + rules: { + "formatjs/enforce-id": [ + "error", + { + idInterpolationPattern: "[sha512:contenthash:base64:6]", + }, + ], + "react/react-in-jsx-scope": "off", + "react-hooks/exhaustive-deps": "off", + "react-refresh/only-export-components": "error", + "simple-import-sort/imports": "error", + "simple-import-sort/exports": "error", + "@typescript-eslint/no-unused-vars": "error", + "max-lines": ["warn", { max: 300, skipBlankLines: true, skipComments: true }], + }, + overrides: [ + { + files: ["*.tsx"], + rules: { + "max-lines": ["warn", { max: 200, skipBlankLines: true, skipComments: true }], + }, + }, + ], + root: true, + ignores: ["build/", "*.test.ts", "*.js"], + env: { + browser: true, + worker: true, + commonjs: true, + node: false, + }, + }, +]; diff --git a/packages/app/package.json b/packages/app/package.json index 296a1199..d298aca5 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -106,6 +106,7 @@ "autoprefixer": "^10.4.16", "config": "^3.3.9", "eslint": "^8.48.0", + "eslint-config-react-app": "^7.0.1", "eslint-plugin-formatjs": "^4.11.3", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", @@ -120,6 +121,7 @@ "tinybench": "^2.5.1", "typescript": "^5.2.2", "vite": "^5.2.8", + "vite-plugin-eslint": "^1.8.1", "vite-plugin-pwa": "^0.19.2", "vite-plugin-version-mark": "^0.0.10", "vitest": "^0.34.6" diff --git a/packages/app/src/Components/Embed/MixCloudEmbed.tsx b/packages/app/src/Components/Embed/MixCloudEmbed.tsx index ffd0359d..b37f60aa 100644 --- a/packages/app/src/Components/Embed/MixCloudEmbed.tsx +++ b/packages/app/src/Components/Embed/MixCloudEmbed.tsx @@ -1,10 +1,10 @@ -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { MixCloudRegex } from "@/Utils/Const"; const MixCloudEmbed = ({ link }: { link: string }) => { const feedPath = (MixCloudRegex.test(link) && RegExp.$1) + "%2F" + (MixCloudRegex.test(link) && RegExp.$2); - const theme = useLogin(s => s.appData.json.preferences.theme); + const theme = usePreferences(s => s.theme); const lightParams = theme === "light" ? "light=1" : "light=0"; return ( <> diff --git a/packages/app/src/Components/Embed/PubkeyList.tsx b/packages/app/src/Components/Embed/PubkeyList.tsx index 7d11cd39..72d69f1b 100644 --- a/packages/app/src/Components/Embed/PubkeyList.tsx +++ b/packages/app/src/Components/Embed/PubkeyList.tsx @@ -8,30 +8,31 @@ import AsyncButton from "@/Components/Button/AsyncButton"; import { Toastore } from "@/Components/Toaster/Toaster"; import FollowListBase from "@/Components/User/FollowListBase"; import useEventPublisher from "@/Hooks/useEventPublisher"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { dedupe, findTag, getDisplayName, hexToBech32 } from "@/Utils"; import { useWallet } from "@/Wallet"; export default function PubkeyList({ ev, className }: { ev: NostrEvent; className?: string }) { const wallet = useWallet(); - const login = useLogin(); - const { publisher } = useEventPublisher(); + const defaultZapAmount = usePreferences(s => s.defaultZapAmount); + const { publisher, system } = useEventPublisher(); const ids = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1])); async function zapAll() { for (const pk of ids) { try { const profile = await UserCache.get(pk); - const amtSend = login.appData.json.preferences.defaultZapAmount; + const amtSend = defaultZapAmount; const lnurl = profile?.lud16 || profile?.lud06; if (lnurl) { const svc = new LNURL(lnurl); await svc.load(); + const relays = await system.requestRouter?.forReplyTo(pk); const zap = await publisher?.zap( amtSend * 1000, pk, - Object.keys(login.relays.item), + relays ?? [], undefined, `Zap from ${hexToBech32("note", ev.id)}`, ); @@ -74,7 +75,7 @@ export default function PubkeyList({ ev, className }: { ev: NostrEvent; classNam defaultMessage="Zap all {n} sats" id="IVbtTS" values={{ - n: , + n: , }} /> diff --git a/packages/app/src/Components/Event/Create/NoteCreator.tsx b/packages/app/src/Components/Event/Create/NoteCreator.tsx index e6fc50d2..f6a1cff6 100644 --- a/packages/app/src/Components/Event/Create/NoteCreator.tsx +++ b/packages/app/src/Components/Event/Create/NoteCreator.tsx @@ -20,6 +20,8 @@ import { Toastore } from "@/Components/Toaster/Toaster"; import ProfileImage from "@/Components/User/ProfileImage"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; +import useRelays from "@/Hooks/useRelays"; import { useNoteCreator } from "@/State/NoteCreator"; import { openFile, trackEvent } from "@/Utils"; import useFileUpload from "@/Utils/Upload"; @@ -56,11 +58,12 @@ const quoteNoteOptions = { export function NoteCreator() { const { formatMessage } = useIntl(); const uploader = useFileUpload(); - const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey, pow: s.appData.json.preferences.pow })); + const publicKey = useLogin(s => s.publicKey); + const pow = usePreferences(s => s.pow); + const relays = useRelays(); const { system, publisher: pub } = useEventPublisher(); - const publisher = login.pow ? pub?.pow(login.pow, GetPowWorker()) : pub; + const publisher = pow ? pub?.pow(pow, GetPowWorker()) : pub; const note = useNoteCreator(); - const relays = login.relays; useEffect(() => { const draft = localStorage.getItem("msgDraft"); @@ -367,8 +370,9 @@ export function NoteCreator() { function renderRelayCustomisation() { return (
- {Object.keys(relays.item || {}) - .filter(el => relays.item[el].write) + {Object.entries(relays) + .filter(el => el[1].write) + .map(a => a[0]) .map((r, i, a) => (
{r}
@@ -523,7 +527,7 @@ export function NoteCreator() {
void }) { const [r, setResult] = useState(rsp); const { formatMessage } = useIntl(); - const { publisher, system } = useEventPublisher(); + const { system } = useEventPublisher(); const login = useLogin(); async function removeRelayFromResult(r: OkResponse) { - if (publisher) { - removeRelay(login, unwrap(sanitizeRelayUrl(r.relay))); - await saveRelays(system, publisher, login.relays.item); - } + await login.state.removeRelay(unwrap(sanitizeRelayUrl(r.relay)), true); close(); } diff --git a/packages/app/src/Components/Event/HiddenNote.tsx b/packages/app/src/Components/Event/HiddenNote.tsx index fb7b2e90..264edf0f 100644 --- a/packages/app/src/Components/Event/HiddenNote.tsx +++ b/packages/app/src/Components/Event/HiddenNote.tsx @@ -1,10 +1,10 @@ import { useState } from "react"; import { FormattedMessage } from "react-intl"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; const HiddenNote = ({ children }: { children: React.ReactNode }) => { - const hideMutedNotes = useLogin(s => s.appData.json.preferences.hideMutedNotes); + const hideMutedNotes = usePreferences(s => s.hideMutedNotes); const [show, setShow] = useState(false); if (hideMutedNotes) return; diff --git a/packages/app/src/Components/Event/Note/NoteContextMenu.tsx b/packages/app/src/Components/Event/Note/NoteContextMenu.tsx index 38d77821..fb773628 100644 --- a/packages/app/src/Components/Event/Note/NoteContextMenu.tsx +++ b/packages/app/src/Components/Event/Note/NoteContextMenu.tsx @@ -1,4 +1,4 @@ -import { HexKey, NostrLink, NostrPrefix } from "@snort/system"; +import { EventKind, HexKey, NostrLink, NostrPrefix } from "@snort/system"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { useEffect, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; @@ -10,7 +10,7 @@ import SnortApi from "@/External/SnortApi"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; import useModeration from "@/Hooks/useModeration"; -import { setBookmarked, setPinned } from "@/Utils/Login"; +import usePreferences from "@/Hooks/usePreferences"; import { getCurrentSubscription, SubscriptionType } from "@/Utils/Subscription"; import { ReBroadcaster } from "../../ReBroadcaster"; @@ -18,7 +18,8 @@ import { ReBroadcaster } from "../../ReBroadcaster"; export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { const { formatMessage } = useIntl(); const login = useLogin(); - const { mute, block } = useModeration(); + const autoTranslate = usePreferences(s => s.autoTranslate); + const { mute } = useModeration(); const { publisher, system } = useEventPublisher(); const [showBroadcast, setShowBroadcast] = useState(false); const lang = window.navigator.language; @@ -26,6 +27,7 @@ export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { type: "language", }); const isMine = ev.pubkey === login.publicKey; + const link = NostrLink.fromEvent(ev); async function deleteEvent() { if (window.confirm(formatMessage(messages.ConfirmDeletion, { id: ev.id.substring(0, 8) })) && publisher) { @@ -78,7 +80,7 @@ export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { useEffect(() => { const sub = getCurrentSubscription(login.subscriptions); - if (sub?.type === SubscriptionType.Premium && (login.appData.json.preferences.autoTranslate ?? true)) { + if (sub?.type === SubscriptionType.Premium && (autoTranslate ?? true)) { translate(); } }, []); @@ -90,19 +92,13 @@ export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { async function pin(id: HexKey) { if (publisher) { - const es = [...login.pinned.item, id]; - const ev = await publisher.pinned(es.map(a => new NostrLink(NostrPrefix.Note, a))); - system.BroadcastEvent(ev); - setPinned(login, es, ev.created_at * 1000); + //todo: PIN note } } async function bookmark(id: string) { if (publisher) { - const es = [...login.bookmarked.item, id]; - const ev = await publisher.bookmarks(es.map(a => new NostrLink(NostrPrefix.Note, a))); - system.BroadcastEvent(ev); - setBookmarked(login, es, ev.created_at * 1000); + //todo: bookmark note } } @@ -132,13 +128,13 @@ export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { - {!login.pinned.item.includes(ev.id) && !login.readonly && ( + {!login.state.isOnList(EventKind.PinList, link) && !login.readonly && ( pin(ev.id)}> )} - {!login.bookmarked.item.includes(ev.id) && !login.readonly && ( + {!login.state.isOnList(EventKind.BookmarksList, link) && !login.readonly && ( bookmark(ev.id)}> @@ -158,12 +154,6 @@ export function NoteContextMenu({ ev, ...props }: NoteContextMenuProps) { - {ev.pubkey !== login.publicKey && !login.readonly && ( - block(ev.pubkey)}> - - - - )} translate()}> diff --git a/packages/app/src/Components/Event/Note/NoteFooter/FooterZapButton.tsx b/packages/app/src/Components/Event/Note/NoteFooter/FooterZapButton.tsx index 94ed42ac..99f64730 100644 --- a/packages/app/src/Components/Event/Note/NoteFooter/FooterZapButton.tsx +++ b/packages/app/src/Components/Event/Note/NoteFooter/FooterZapButton.tsx @@ -11,6 +11,7 @@ import { ZapsSummary } from "@/Components/Event/ZapsSummary"; import ZapModal from "@/Components/ZapModal/ZapModal"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { getDisplayName } from "@/Utils"; import { Zapper, ZapTarget } from "@/Utils/Zapper"; import { ZapPoolController } from "@/Utils/ZapPoolController"; @@ -23,15 +24,11 @@ export interface ZapIconProps { } export const FooterZapButton = ({ ev, zaps, onClickZappers }: ZapIconProps) => { - const { - publicKey, - readonly, - preferences: prefs, - } = useLogin(s => ({ + const { publicKey, readonly } = useLogin(s => ({ publicKey: s.publicKey, readonly: s.readonly, - preferences: s.appData.json.preferences, })); + const preferences = usePreferences(s => ({ autoZap: s.autoZap, defaultZapAmount: s.defaultZapAmount })); const walletState = useWallet(); const wallet = walletState.wallet; const link = NostrLink.fromEvent(ev); @@ -75,7 +72,7 @@ export const FooterZapButton = ({ ev, zaps, onClickZappers }: ZapIconProps) => { if (canFastZap && lnurl) { setZapping(true); try { - await fastZapInner(lnurl, prefs.defaultZapAmount); + await fastZapInner(lnurl, preferences.defaultZapAmount); } catch (e) { console.warn("Fast zap failed", e); if (!(e instanceof Error) || e.message !== "User rejected") { @@ -110,13 +107,13 @@ export const FooterZapButton = ({ ev, zaps, onClickZappers }: ZapIconProps) => { const targets = getZapTarget(); useEffect(() => { - if (prefs.autoZap && !didZap && !isMine && !zapping) { + if (preferences.autoZap && !didZap && !isMine && !zapping) { const lnurl = getZapTarget(); if (wallet?.isReady() && lnurl) { setZapping(true); queueMicrotask(async () => { try { - await fastZapInner(lnurl, prefs.defaultZapAmount); + await fastZapInner(lnurl, preferences.defaultZapAmount); } catch { // ignored } finally { @@ -125,7 +122,7 @@ export const FooterZapButton = ({ ev, zaps, onClickZappers }: ZapIconProps) => { }); } } - }, [prefs.autoZap, author, zapping]); + }, [preferences.autoZap, author, zapping]); return ( <> diff --git a/packages/app/src/Components/Event/Note/NoteFooter/NoteFooter.tsx b/packages/app/src/Components/Event/Note/NoteFooter/NoteFooter.tsx index 439a53d7..d1d07c5c 100644 --- a/packages/app/src/Components/Event/Note/NoteFooter/NoteFooter.tsx +++ b/packages/app/src/Components/Event/Note/NoteFooter/NoteFooter.tsx @@ -9,6 +9,7 @@ import { ReplyButton } from "@/Components/Event/Note/NoteFooter/ReplyButton"; import { RepostButton } from "@/Components/Event/Note/NoteFooter/RepostButton"; import ReactionsModal from "@/Components/Event/Note/ReactionsModal"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; export interface NoteFooterProps { replyCount?: number; @@ -25,17 +26,14 @@ export default function NoteFooter(props: NoteFooterProps) { const { replies, reactions, zaps, reposts } = useEventReactions(link, related); const { positive } = reactions; - const { preferences: prefs, readonly } = useLogin(s => ({ - preferences: s.appData.json.preferences, - publicKey: s.publicKey, - readonly: s.readonly, - })); + const readonly = useLogin(s => s.readonly); + const enableReactions = usePreferences(s => s.enableReactions); return (
- {prefs.enableReactions && } + {enableReactions && } {CONFIG.showPowIcon && } setShowReactions(true)} /> {showReactions && setShowReactions(false)} event={ev} />} diff --git a/packages/app/src/Components/Event/Note/NoteFooter/RepostButton.tsx b/packages/app/src/Components/Event/Note/NoteFooter/RepostButton.tsx index 368c0d8b..4b3c681f 100644 --- a/packages/app/src/Components/Event/Note/NoteFooter/RepostButton.tsx +++ b/packages/app/src/Components/Event/Note/NoteFooter/RepostButton.tsx @@ -9,16 +9,15 @@ import Icon from "@/Components/Icons/Icon"; import messages from "@/Components/messages"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { useNoteCreator } from "@/State/NoteCreator"; export const RepostButton = ({ ev, reposts }: { ev: TaggedNostrEvent; reposts: TaggedNostrEvent[] }) => { const { formatMessage } = useIntl(); const navigate = useNavigate(); const { publisher, system } = useEventPublisher(); - const { publicKey, preferences: prefs } = useLogin(s => ({ - preferences: s.appData.json.preferences, - publicKey: s.publicKey, - })); + const publicKey = useLogin(s => s.publicKey); + const confirmReposts = usePreferences(s => s.confirmReposts); const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update, quote: n.quote })); const hasReposted = () => { @@ -27,7 +26,7 @@ export const RepostButton = ({ ev, reposts }: { ev: TaggedNostrEvent; reposts: T const repost = async () => { if (!hasReposted() && publisher) { - if (!prefs.confirmReposts || window.confirm(formatMessage(messages.ConfirmRepost, { id: ev.id }))) { + if (!confirmReposts || window.confirm(formatMessage(messages.ConfirmRepost, { id: ev.id }))) { const evRepost = await publisher.repost(ev); system.BroadcastEvent(evRepost); } diff --git a/packages/app/src/Components/Event/Note/NoteHeader.tsx b/packages/app/src/Components/Event/Note/NoteHeader.tsx index 64442de0..5855e1ad 100644 --- a/packages/app/src/Components/Event/Note/NoteHeader.tsx +++ b/packages/app/src/Components/Event/Note/NoteHeader.tsx @@ -1,4 +1,4 @@ -import { HexKey, NostrLink, NostrPrefix, TaggedNostrEvent } from "@snort/system"; +import { EventKind, NostrLink, TaggedNostrEvent } from "@snort/system"; import React, { useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; @@ -13,7 +13,6 @@ import messages from "@/Components/messages"; import ProfileImage from "@/Components/User/ProfileImage"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; -import { setBookmarked, setPinned } from "@/Utils/Login"; export default function NoteHeader(props: { ev: TaggedNostrEvent; @@ -24,28 +23,21 @@ export default function NoteHeader(props: { const [showReactions, setShowReactions] = useState(false); const { ev, options, setTranslated } = props; const { formatMessage } = useIntl(); - const { pinned, bookmarked } = useLogin(); - const { publisher, system } = useEventPublisher(); + const { publisher } = useEventPublisher(); const login = useLogin(); - async function unpin(id: HexKey) { + async function unpin() { if (options.canUnpin && publisher) { if (window.confirm(formatMessage(messages.ConfirmUnpin))) { - const es = pinned.item.filter(e => e !== id); - const ev = await publisher.pinned(es.map(a => new NostrLink(NostrPrefix.Note, a))); - system.BroadcastEvent(ev); - setPinned(login, es, ev.created_at * 1000); + await login.state.removeFromList(EventKind.PinList, NostrLink.fromEvent(ev)); } } } - async function unbookmark(id: HexKey) { + async function unbookmark() { if (options.canUnbookmark && publisher) { if (window.confirm(formatMessage(messages.ConfirmUnbookmark))) { - const es = bookmarked.item.filter(e => e !== id); - const ev = await publisher.pinned(es.map(a => new NostrLink(NostrPrefix.Note, a))); - system.BroadcastEvent(ev); - setBookmarked(login, es, ev.created_at * 1000); + await login.state.removeFromList(EventKind.BookmarksList, NostrLink.fromEvent(ev)); } } } @@ -66,7 +58,7 @@ export default function NoteHeader(props: { {(options.showTime || options.showBookmarked) && ( <> {options.showBookmarked && ( -
unbookmark(ev.id)}> +
unbookmark()}>
)} @@ -74,7 +66,7 @@ export default function NoteHeader(props: { )} {options.showPinned && ( -
unpin(ev.id)}> +
unpin()}>
)} diff --git a/packages/app/src/Components/Event/Note/NoteText.tsx b/packages/app/src/Components/Event/Note/NoteText.tsx index d93f19b9..1a7275a5 100644 --- a/packages/app/src/Components/Event/Note/NoteText.tsx +++ b/packages/app/src/Components/Event/Note/NoteText.tsx @@ -6,14 +6,14 @@ import { NoteProps } from "@/Components/Event/EventComponent"; import { NoteTranslation } from "@/Components/Event/Note/types"; import Reveal from "@/Components/Event/Reveal"; import Text from "@/Components/Text/Text"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; const TEXT_TRUNCATE_LENGTH = 400; export const NoteText = memo(function InnerContent( props: NoteProps & { translated: NoteTranslation; showTranslation?: boolean }, ) { const { data: ev, options, translated, showTranslation } = props; - const appData = useLogin(s => s.appData); + const showContentWarningPosts = usePreferences(s => s.showContentWarningPosts); const [showMore, setShowMore] = useState(false); const body = translated && !translated.skipped && showTranslation ? translated.text : ev?.content ?? ""; const id = translated && !translated.skipped && showTranslation ? `${ev.id}-translated` : ev.id; @@ -53,7 +53,7 @@ export const NoteText = memo(function InnerContent( ); - if (!appData.json.showContentWarningPosts) { + if (!showContentWarningPosts) { const contentWarning = ev.tags.find(a => a[0] === "content-warning"); if (contentWarning) { return ( diff --git a/packages/app/src/Components/Event/Poll.tsx b/packages/app/src/Components/Event/Poll.tsx index 48f980b0..02bf129b 100644 --- a/packages/app/src/Components/Event/Poll.tsx +++ b/packages/app/src/Components/Event/Poll.tsx @@ -8,6 +8,7 @@ import Spinner from "@/Components/Icons/Spinner"; import ZapModal from "@/Components/ZapModal/ZapModal"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { unwrap } from "@/Utils"; import { formatShort } from "@/Utils/Number"; import { useWallet } from "@/Wallet"; @@ -21,13 +22,10 @@ type PollTally = "zaps" | "pubkeys"; export default function Poll(props: PollProps) { const { formatMessage } = useIntl(); - const { publisher } = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const { wallet } = useWallet(); - const { - preferences: prefs, - publicKey: myPubKey, - relays, - } = useLogin(s => ({ preferences: s.appData.json.preferences, publicKey: s.publicKey, relays: s.relays })); + const defaultZapAmount = usePreferences(s => s.defaultZapAmount); + const myPubKey = useLogin(s => s.publicKey); const pollerProfile = useUserProfile(props.ev.pubkey); const [tallyBy, setTallyBy] = useState("pubkeys"); const [error, setError] = useState(""); @@ -45,7 +43,7 @@ export default function Poll(props: PollProps) { ev.stopPropagation(); if (voting || !publisher) return; - const amount = prefs.defaultZapAmount; + const amount = defaultZapAmount; try { if (amount <= 0) { throw new Error( @@ -62,9 +60,14 @@ export default function Poll(props: PollProps) { } setVoting(opt); - const r = Object.keys(relays.item); - const zap = await publisher.zap(amount * 1000, props.ev.pubkey, r, NostrLink.fromEvent(props.ev), undefined, eb => - eb.tag(["poll_option", opt.toString()]), + const r = await system.requestRouter?.forReplyTo(props.ev.pubkey); + const zap = await publisher.zap( + amount * 1000, + props.ev.pubkey, + r ?? [], + NostrLink.fromEvent(props.ev), + undefined, + eb => eb.tag(["poll_option", opt.toString()]), ); const lnurl = props.ev.tags.find(a => a[0] === "zap")?.[1] || pollerProfile?.lud16 || pollerProfile?.lud06; @@ -121,7 +124,7 @@ export default function Poll(props: PollProps) { defaultMessage="You are voting with {amount} sats" id="3qnJlS" values={{ - amount: formatShort(prefs.defaultZapAmount), + amount: formatShort(defaultZapAmount), }} /> diff --git a/packages/app/src/Components/Event/RevealMedia.tsx b/packages/app/src/Components/Event/RevealMedia.tsx index 73fd85c2..8f6086df 100644 --- a/packages/app/src/Components/Event/RevealMedia.tsx +++ b/packages/app/src/Components/Event/RevealMedia.tsx @@ -6,6 +6,7 @@ import { MediaElement } from "@/Components/Embed/MediaElement"; import Reveal from "@/Components/Event/Reveal"; import useFollowsControls from "@/Hooks/useFollowControls"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { FileExtensionRegex } from "@/Utils/Const"; interface RevealMediaProps { @@ -17,15 +18,13 @@ interface RevealMediaProps { } export default function RevealMedia(props: RevealMediaProps) { - const { preferences, publicKey } = useLogin(s => ({ - preferences: s.appData.json.preferences, - publicKey: s.publicKey, - })); + const publicKey = useLogin(s => s.publicKey); + const autoLoadMedia = usePreferences(s => s.autoLoadMedia); const { isFollowing } = useFollowsControls(); - const hideNonFollows = preferences.autoLoadMedia === "follows-only" && !isFollowing(props.creator); + const hideNonFollows = autoLoadMedia === "follows-only" && !isFollowing(props.creator); const isMine = props.creator === publicKey; - const hideMedia = preferences.autoLoadMedia === "none" || (!isMine && hideNonFollows); + const hideMedia = autoLoadMedia === "none" || (!isMine && hideNonFollows); const hostname = new URL(props.link).hostname; const url = new URL(props.link); diff --git a/packages/app/src/Components/Event/Thread/Thread.tsx b/packages/app/src/Components/Event/Thread/Thread.tsx index 1fbcecc6..b7df3173 100644 --- a/packages/app/src/Components/Event/Thread/Thread.tsx +++ b/packages/app/src/Components/Event/Thread/Thread.tsx @@ -123,8 +123,6 @@ export function Thread(props: { onBack?: () => void; disableSpotlight?: boolean
{JSON.stringify(thread.root, undefined, "  ")}

Data

{JSON.stringify(thread.data, undefined, "  ")}
-

Reactions

-
{JSON.stringify(thread.reactions, undefined, "  ")}
)} {parent && ( diff --git a/packages/app/src/Components/Feed/RootTabItems.tsx b/packages/app/src/Components/Feed/RootTabItems.tsx index b1ea0930..a0382cc3 100644 --- a/packages/app/src/Components/Feed/RootTabItems.tsx +++ b/packages/app/src/Components/Feed/RootTabItems.tsx @@ -3,9 +3,8 @@ import { FormattedMessage } from "react-intl"; import Icon from "@/Components/Icons/Icon"; import { RootTabRoutePath } from "@/Pages/Root/RootTabRoutes"; -import { Newest } from "@/Utils/Login"; -export function rootTabItems(base: string, pubKey: string | undefined, tags: Newest>) { +export function rootTabItems(base: string, pubKey: string | undefined, tags: Array) { const menuItems = [ { tab: "for-you", @@ -98,7 +97,7 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New { tab: "tags", path: `${base}/topics`, - show: tags.item.length > 0, + show: tags.length > 0, element: ( <> diff --git a/packages/app/src/Components/Feed/RootTabs.tsx b/packages/app/src/Components/Feed/RootTabs.tsx index 757713c0..02301cc3 100644 --- a/packages/app/src/Components/Feed/RootTabs.tsx +++ b/packages/app/src/Components/Feed/RootTabs.tsx @@ -7,26 +7,26 @@ import { useLocation, useNavigate } from "react-router-dom"; import { rootTabItems } from "@/Components/Feed/RootTabItems"; import Icon from "@/Components/Icons/Icon"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { RootTabRoutePath } from "@/Pages/Root/RootTabRoutes"; +import { EventKind } from "@snort/system"; +import { unwrap } from "@snort/shared"; export function RootTabs({ base = "/" }: { base: string }) { const navigate = useNavigate(); const location = useLocation(); - const { - publicKey: pubKey, - tags, - preferences, - } = useLogin(s => ({ + const { publicKey: pubKey, tags } = useLogin(s => ({ publicKey: s.publicKey, - tags: s.tags, - preferences: s.appData.json.preferences, + tags: s.state.getList(EventKind.InterestSet), })); + const defaultRootTab = usePreferences(s => s.defaultRootTab); - const menuItems = useMemo(() => rootTabItems(base, pubKey, tags), [base, pubKey, tags]); + const hashTags = tags.filter(a => a.toEventTag()?.[0] === "t").map(a => unwrap(a.toEventTag())[1]); + const menuItems = useMemo(() => rootTabItems(base, pubKey, hashTags), [base, pubKey, tags]); let defaultTab: RootTabRoutePath; if (pubKey) { - defaultTab = preferences.defaultRootTab; + defaultTab = defaultRootTab; } else { defaultTab = `trending/notes`; } diff --git a/packages/app/src/Components/Feed/TimelineFollows.tsx b/packages/app/src/Components/Feed/TimelineFollows.tsx index 72c3dfb0..667996b2 100644 --- a/packages/app/src/Components/Feed/TimelineFollows.tsx +++ b/packages/app/src/Components/Feed/TimelineFollows.tsx @@ -26,7 +26,11 @@ export interface TimelineFollowsProps { * A list of notes by "subject" */ const TimelineFollows = (props: TimelineFollowsProps) => { - const login = useLogin(); + const login = useLogin(s => ({ + publicKey: s.publicKey, + feedDisplayAs: s.feedDisplayAs, + tags: s.state.getList(EventKind.InterestSet), + })); const displayAsInitial = props.displayAs ?? login.feedDisplayAs ?? "list"; const [displayAs, setDisplayAs] = useState(displayAsInitial); const [openedAt] = useHistoryState(Math.floor(Date.now() / 1000), "openedAt"); @@ -38,12 +42,12 @@ const TimelineFollows = (props: TimelineFollowsProps) => { items: followList, discriminator: login.publicKey?.slice(0, 12), extra: rb => { - if (login.tags.item.length > 0) { - rb.withFilter().kinds([EventKind.TextNote, EventKind.Repost]).tag("t", login.tags.item); + if (login.tags.length > 0) { + rb.withFilter().kinds([EventKind.TextNote, EventKind.Repost]).tags(login.tags); } }, }) as TimelineSubject, - [followList, login.tags.item], + [login.publicKey, followList, login.tags], ); const feed = useTimelineFeed(subject, { method: "TIME_RANGE", now: openedAt } as TimelineFeedOptions); diff --git a/packages/app/src/Components/Feed/UsersFeed.tsx b/packages/app/src/Components/Feed/UsersFeed.tsx index 7a536cba..ef5fc4ad 100644 --- a/packages/app/src/Components/Feed/UsersFeed.tsx +++ b/packages/app/src/Components/Feed/UsersFeed.tsx @@ -16,12 +16,12 @@ export default function UsersFeed({ keyword, sortPopular = true }: { keyword: st { method: "LIMIT_UNTIL" }, ); - const { muted, isEventMuted } = useModeration(); + const { isEventMuted } = useModeration(); const filterPosts = useCallback( (nts: readonly TaggedNostrEvent[]) => { return nts.filter(a => !isEventMuted(a)); }, - [muted], + [isEventMuted], ); const usersFeed = useMemo(() => filterPosts(feed.main ?? []).map(p => p.pubkey), [feed, filterPosts]); diff --git a/packages/app/src/Components/IntlProvider/useLocale.tsx b/packages/app/src/Components/IntlProvider/useLocale.tsx index 0ea7f7c9..2abfb75d 100644 --- a/packages/app/src/Components/IntlProvider/useLocale.tsx +++ b/packages/app/src/Components/IntlProvider/useLocale.tsx @@ -2,10 +2,10 @@ import { useSyncExternalStore } from "react"; import { getLocale } from "@/Components/IntlProvider/IntlProviderUtils"; import { LangOverride } from "@/Components/IntlProvider/langStore"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; export function useLocale() { - const { language } = useLogin(s => ({ language: s.appData.json.preferences.language })); + const language = usePreferences(s => s.language); const loggedOutLang = useSyncExternalStore( c => LangOverride.hook(c), () => LangOverride.snapshot(), diff --git a/packages/app/src/Components/PinPrompt/PinPrompt.tsx b/packages/app/src/Components/PinPrompt/PinPrompt.tsx index 787de4b1..8ed0ac1a 100644 --- a/packages/app/src/Components/PinPrompt/PinPrompt.tsx +++ b/packages/app/src/Components/PinPrompt/PinPrompt.tsx @@ -7,6 +7,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { createPublisher, LoginStore, sessionNeedsPin } from "@/Utils/Login"; import { GetPowWorker } from "@/Utils/wasm"; @@ -97,6 +98,7 @@ export function PinPrompt({ export function LoginUnlock() { const login = useLogin(); + const pow = usePreferences(s => s.pow); const { publisher } = useEventPublisher(); async function encryptMigration(pin: string) { @@ -104,8 +106,8 @@ export function LoginUnlock() { const newPin = await PinEncrypted.create(k, pin); const pub = EventPublisher.privateKey(k); - if (login.appData.json.preferences.pow) { - pub.pow(login.appData.json.preferences.pow, GetPowWorker()); + if (pow) { + pub.pow(pow, GetPowWorker()); } LoginStore.setPublisher(login.id, pub); LoginStore.updateSession({ @@ -121,8 +123,8 @@ export function LoginUnlock() { await key.unlock(pin); const pub = createPublisher(login); if (pub) { - if (login.appData.json.preferences.pow) { - pub.pow(login.appData.json.preferences.pow, GetPowWorker()); + if (pow) { + pub.pow(pow, GetPowWorker()); } LoginStore.setPublisher(login.id, pub); LoginStore.updateSession({ diff --git a/packages/app/src/Components/ReBroadcaster.tsx b/packages/app/src/Components/ReBroadcaster.tsx index 3d241ddb..a2077b67 100644 --- a/packages/app/src/Components/ReBroadcaster.tsx +++ b/packages/app/src/Components/ReBroadcaster.tsx @@ -4,7 +4,7 @@ import { useContext, useState } from "react"; import { FormattedMessage } from "react-intl"; import Modal from "@/Components/Modal/Modal"; -import useLogin from "@/Hooks/useLogin"; +import useRelays from "@/Hooks/useRelays"; import AsyncButton from "./Button/AsyncButton"; import messages from "./messages"; @@ -12,7 +12,7 @@ import messages from "./messages"; export function ReBroadcaster({ onClose, ev }: { onClose: () => void; ev: TaggedNostrEvent }) { const [selected, setSelected] = useState>(); const system = useContext(SnortContext); - const { relays } = useLogin(s => ({ relays: s.relays })); + const relays = useRelays(); async function sendReBroadcast() { if (selected) { @@ -25,8 +25,8 @@ export function ReBroadcaster({ onClose, ev }: { onClose: () => void; ev: Tagged function renderRelayCustomisation() { return (
- {Object.keys(relays.item || {}) - .filter(el => relays.item[el].write) + {Object.keys(relays) + .filter(el => relays[el].write) .map((r, i, a) => (
{r}
@@ -36,7 +36,7 @@ export function ReBroadcaster({ onClose, ev }: { onClose: () => void; ev: Tagged checked={!selected || selected.includes(r)} onChange={e => setSelected( - e.target.checked && selected && selected.length == a.length - 1 + e.target.checked && selected && selected.length === a.length - 1 ? undefined : a.filter(el => (el === r ? e.target.checked : !selected || selected.includes(el))), ) diff --git a/packages/app/src/Components/Relay/Relay.tsx b/packages/app/src/Components/Relay/Relay.tsx index 50eb44ae..7d861e9d 100644 --- a/packages/app/src/Components/Relay/Relay.tsx +++ b/packages/app/src/Components/Relay/Relay.tsx @@ -1,17 +1,14 @@ import "./Relay.css"; -import { unixNowMs } from "@snort/shared"; import { RelaySettings } from "@snort/system"; -import { SnortContext } from "@snort/system-react"; import classNames from "classnames"; -import { useContext, useMemo } from "react"; +import { useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { AsyncIcon } from "@/Components/Button/AsyncIcon"; import useRelayState from "@/Feed/RelayState"; import useLogin from "@/Hooks/useLogin"; -import { getRelayName, unwrap } from "@/Utils"; -import { removeRelay, setRelays } from "@/Utils/Login"; +import { getRelayName } from "@/Utils"; import { RelayFavicon } from "./RelaysMetadata"; @@ -21,35 +18,29 @@ export interface RelayProps { export default function Relay(props: RelayProps) { const navigate = useNavigate(); - const system = useContext(SnortContext); - const login = useLogin(); + const state = useLogin(s => s.state); - const relaySettings = unwrap(login.relays.item[props.addr] ?? system.pool.getConnection(props.addr)?.Settings ?? {}); - const state = useRelayState(props.addr); const name = useMemo(() => getRelayName(props.addr), [props.addr]); + const connection = useRelayState(props.addr); - function configure(o: RelaySettings) { - setRelays( - login, - { - ...login.relays.item, - [props.addr]: o, - }, - unixNowMs(), - ); + const relaySettings = state.relays?.find(a => a.url === props.addr)?.settings; + if (!relaySettings || !connection) return; + + async function configure(o: RelaySettings) { + await state.updateRelay(props.addr, o); } return ( <>
-
+
{name}
- {!state?.Ephemeral && ( + {!connection?.Ephemeral && (
removeRelay(login, props.addr)} + onClick={() => state.removeRelay(props.addr)} /> navigate(state?.Id ?? "")} + onClick={() => navigate(connection?.Id ?? "")} />
)} diff --git a/packages/app/src/Components/SuggestedProfiles.tsx b/packages/app/src/Components/SuggestedProfiles.tsx index a311d52f..670b0fd6 100644 --- a/packages/app/src/Components/SuggestedProfiles.tsx +++ b/packages/app/src/Components/SuggestedProfiles.tsx @@ -17,15 +17,15 @@ enum Provider { } export default function SuggestedProfiles() { - const login = useLogin(s => ({ publicKey: s.publicKey, follows: s.contacts })); + const publicKey = useLogin(s => s.publicKey); const [provider, setProvider] = useState(Provider.NostrBand); const getUrlAndKey = () => { - if (!login.publicKey) return { url: null, key: null }; + if (!publicKey) return { url: null, key: null }; switch (provider) { case Provider.NostrBand: { const api = new NostrBandApi(); - const url = api.suggestedFollowsUrl(hexToBech32(NostrPrefix.PublicKey, login.publicKey)); + const url = api.suggestedFollowsUrl(hexToBech32(NostrPrefix.PublicKey, publicKey)); return { url, key: `nostr-band-${url}` }; } default: diff --git a/packages/app/src/Components/Trending/TrendingPosts.tsx b/packages/app/src/Components/Trending/TrendingPosts.tsx index 4a545ff9..a0f3f61a 100644 --- a/packages/app/src/Components/Trending/TrendingPosts.tsx +++ b/packages/app/src/Components/Trending/TrendingPosts.tsx @@ -33,7 +33,7 @@ export default function TrendingNotes({ count = Infinity, small = false }: { cou const ev = a.event; if (!System.optimizer.schnorrVerify(ev)) { console.error(`Event with invalid sig\n\n${ev}\n\nfrom ${trendingNotesUrl}`); - return; + return undefined; } System.HandleEvent("*", ev as TaggedNostrEvent); return ev; diff --git a/packages/app/src/Components/User/BlockButton.tsx b/packages/app/src/Components/User/BlockButton.tsx deleted file mode 100644 index d2ae0da5..00000000 --- a/packages/app/src/Components/User/BlockButton.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { HexKey } from "@snort/system"; -import { FormattedMessage } from "react-intl"; - -import useModeration from "@/Hooks/useModeration"; - -import messages from "../messages"; - -interface BlockButtonProps { - pubkey: HexKey; -} - -const BlockButton = ({ pubkey }: BlockButtonProps) => { - const { block, unblock, isBlocked } = useModeration(); - return isBlocked(pubkey) ? ( - - ) : ( - - ); -}; - -export default BlockButton; diff --git a/packages/app/src/Components/User/BlockList.tsx b/packages/app/src/Components/User/BlockList.tsx deleted file mode 100644 index 46b8fd2d..00000000 --- a/packages/app/src/Components/User/BlockList.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import BlockButton from "@/Components/User/BlockButton"; -import ProfilePreview from "@/Components/User/ProfilePreview"; -import useModeration from "@/Hooks/useModeration"; - -export default function BlockList() { - const { blocked } = useModeration(); - - return ( -
- {blocked.map(a => { - return } pubkey={a} options={{ about: false }} key={a} />; - })} -
- ); -} diff --git a/packages/app/src/Components/User/MutedList.tsx b/packages/app/src/Components/User/MutedList.tsx index 5487b37b..8bd360ea 100644 --- a/packages/app/src/Components/User/MutedList.tsx +++ b/packages/app/src/Components/User/MutedList.tsx @@ -1,4 +1,4 @@ -import { HexKey } from "@snort/system"; +import { HexKey, NostrPrefix } from "@snort/system"; import { FormattedMessage } from "react-intl"; import MuteButton from "@/Components/User/MuteButton"; @@ -11,26 +11,31 @@ export interface MutedListProps { pubkeys: HexKey[]; } -export default function MutedList({ pubkeys }: MutedListProps) { - const { isMuted, muteAll } = useModeration(); - const hasAllMuted = pubkeys.every(isMuted); +export default function MutedList() { + const { muteList } = useModeration(); return (
- +
-
- {pubkeys?.map(a => { - return } pubkey={a} options={{ about: false }} key={a} />; + {muteList?.map(a => { + switch (a.type) { + case NostrPrefix.Profile: + case NostrPrefix.PublicKey: { + return ( + } + pubkey={a.id} + options={{ about: false }} + key={a.id} + /> + ); + } + } + return undefined; })}
); diff --git a/packages/app/src/Components/ZapModal/ZapModalInput.tsx b/packages/app/src/Components/ZapModal/ZapModalInput.tsx index c692d05a..dc1eddea 100644 --- a/packages/app/src/Components/ZapModal/ZapModalInput.tsx +++ b/packages/app/src/Components/ZapModal/ZapModalInput.tsx @@ -7,6 +7,7 @@ import messages from "@/Components/messages"; import { ZapType } from "@/Components/ZapModal/ZapType"; import { ZapTypeSelector } from "@/Components/ZapModal/ZapTypeSelector"; import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { formatShort } from "@/Utils/Number"; import { Zapper } from "@/Utils/Zapper"; @@ -21,10 +22,8 @@ export function ZapModalInput(props: { onChange?: (v: SendSatsInputSelection) => void; onNextStage: (v: SendSatsInputSelection) => Promise; }) { - const { defaultZapAmount, readonly } = useLogin(s => ({ - defaultZapAmount: s.appData.json.preferences.defaultZapAmount, - readonly: s.readonly, - })); + const defaultZapAmount = usePreferences(s => s.defaultZapAmount); + const readonly = useLogin(s => s.readonly); const { formatMessage } = useIntl(); const amounts: Record = { [defaultZapAmount.toString()]: "", diff --git a/packages/app/src/Feed/ArticlesFeed.ts b/packages/app/src/Feed/ArticlesFeed.ts index fae90ffb..e34e91ea 100644 --- a/packages/app/src/Feed/ArticlesFeed.ts +++ b/packages/app/src/Feed/ArticlesFeed.ts @@ -5,15 +5,15 @@ import { useMemo } from "react"; import useLogin from "@/Hooks/useLogin"; export function useArticles() { - const { publicKey, follows } = useLogin(); + const { publicKey, follows } = useLogin(s => ({ publicKey: s.publicKey, follows: s.state.follows })); const sub = useMemo(() => { if (!publicKey) return null; const rb = new RequestBuilder(`articles:${publicKey}`); - rb.withFilter().kinds([EventKind.LongFormTextNote]).authors(follows.item).limit(20); + rb.withFilter().kinds([EventKind.LongFormTextNote]).authors(follows).limit(20); return rb; - }, [follows.timestamp]); + }, [follows, publicKey]); return useRequestBuilder(sub); } diff --git a/packages/app/src/Feed/FollowsFeed.ts b/packages/app/src/Feed/FollowsFeed.ts index fb5157ea..9f58e035 100644 --- a/packages/app/src/Feed/FollowsFeed.ts +++ b/packages/app/src/Feed/FollowsFeed.ts @@ -5,7 +5,7 @@ import { useMemo } from "react"; import useLogin from "@/Hooks/useLogin"; export default function useFollowsFeed(pubkey?: HexKey) { - const { publicKey, follows } = useLogin(); + const { publicKey, follows } = useLogin(s => ({ publicKey: s.publicKey, follows: s.state.follows })); const isMe = publicKey === pubkey; const sub = useMemo(() => { @@ -18,11 +18,11 @@ export default function useFollowsFeed(pubkey?: HexKey) { const contactFeed = useRequestBuilder(sub); return useMemo(() => { if (isMe) { - return follows.item; + return follows; } return getFollowing(contactFeed ?? [], pubkey); - }, [contactFeed, follows, pubkey]); + }, [isMe, contactFeed, follows, pubkey]); } export function getFollowing(notes: readonly TaggedNostrEvent[], pubkey?: HexKey) { diff --git a/packages/app/src/Feed/LoginFeed.ts b/packages/app/src/Feed/LoginFeed.ts index fa771ab9..f6ab5055 100644 --- a/packages/app/src/Feed/LoginFeed.ts +++ b/packages/app/src/Feed/LoginFeed.ts @@ -1,42 +1,33 @@ -import { EventKind, NostrLink, parseRelayTags, RequestBuilder, TaggedNostrEvent } from "@snort/system"; +import { EventKind, RequestBuilder } from "@snort/system"; import { useRequestBuilder } from "@snort/system-react"; import { useEffect, useMemo } from "react"; -import { Nip28ChatSystem } from "@/chat/nip28"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; -import { bech32ToHex, getNewest, getNewestEventTagsByKey, unwrap } from "@/Utils"; +import usePreferences from "@/Hooks/usePreferences"; +import { bech32ToHex, unwrap } from "@/Utils"; import { SnortPubKey } from "@/Utils/Const"; -import { - addSubscription, - LoginStore, - setBlocked, - setBookmarked, - setMuted, - setPinned, - setRelays, - setTags, - updateSession, -} from "@/Utils/Login"; +import { addSubscription } from "@/Utils/Login"; import { SubscriptionEvent } from "@/Utils/Subscription"; + /** * Managed loading data for the current logged in user */ export default function useLoginFeed() { const login = useLogin(); - const { publicKey: pubKey, contacts } = login; + const { publicKey: pubKey } = login; + const checkSigs = usePreferences(s => s.checkSigs); const { publisher, system } = useEventPublisher(); useEffect(() => { - if (login.appData.json) { - system.checkSigs = login.appData.json.preferences.checkSigs; + system.checkSigs = checkSigs; + }, [system, checkSigs]); - if (publisher) { - login.appData.sync(publisher.signer, system); - } + useEffect(() => { + if (publisher) { + login.state.init(publisher.signer, system).catch(console.error); } - }, [login, publisher]); - + }, [login, publisher, system]); const subLogin = useMemo(() => { if (!login || !pubKey) return null; @@ -44,18 +35,7 @@ export default function useLoginFeed() { b.withOptions({ leaveOpen: true, }); - b.withFilter() - .authors([pubKey]) - .kinds([ - EventKind.ContactList, - EventKind.Relays, - EventKind.MuteList, - EventKind.PinList, - EventKind.BookmarksList, - EventKind.InterestsList, - EventKind.PublicChatsList, - EventKind.DirectMessage, - ]); + b.withFilter().authors([pubKey]).kinds([EventKind.DirectMessage]); if (CONFIG.features.subscriptions && !login.readonly) { b.withFilter() .relay("wss://relay.snort.social/") @@ -66,121 +46,32 @@ export default function useLoginFeed() { } return b; - }, [login]); + }, [pubKey, login]); const loginFeed = useRequestBuilder(subLogin); // update relays and follow lists useEffect(() => { - if (loginFeed) { - const contactList = getNewest(loginFeed.filter(a => a.kind === EventKind.ContactList)); - if (contactList) { - updateSession(login.id, s => { - s.contacts = contactList.tags; - }); - } - - const relays = getNewest(loginFeed.filter(a => a.kind === EventKind.Relays)); - if (relays) { - const parsedRelays = parseRelayTags(relays.tags.filter(a => a[0] === "r")).map(a => [a.url, a.settings]); - setRelays(login, Object.fromEntries(parsedRelays), relays.created_at * 1000); - } - - if (publisher) { - const subs = loginFeed.filter( - a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey), - ); - Promise.all( - subs.map(async a => { - const dx = await publisher.decryptDm(a); - if (dx) { - const ex = JSON.parse(dx); - return { - id: a.id, - ...ex, - } as SubscriptionEvent; - } - }), - ).then(a => addSubscription(login, ...a.filter(a => a !== undefined).map(unwrap))); - } + if (loginFeed && publisher) { + const subs = loginFeed.filter( + a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey), + ); + Promise.all( + subs.map(async a => { + const dx = await publisher.decryptDm(a); + if (dx) { + const ex = JSON.parse(dx); + return { + id: a.id, + ...ex, + } as SubscriptionEvent; + } + }), + ).then(a => addSubscription(login, ...a.filter(a => a !== undefined).map(unwrap))); } - }, [loginFeed, publisher]); - - async function handleMutedFeed(mutedFeed: TaggedNostrEvent[]) { - const latest = getNewest(mutedFeed); - if (!latest) return; - - const muted = NostrLink.fromTags(latest.tags); - setMuted( - login, - muted.map(a => a.id), - latest.created_at * 1000, - ); - - if (latest?.content && publisher && pubKey) { - try { - const privMutes = await publisher.nip4Decrypt(latest.content, pubKey); - const blocked = JSON.parse(privMutes) as Array>; - const keys = blocked.filter(a => a[0] === "p").map(a => a[1]); - setBlocked(login, keys, latest.created_at * 1000); - } catch (error) { - console.debug("Failed to parse mute list", error, latest); - } - } - } - - function handlePinnedFeed(pinnedFeed: TaggedNostrEvent[]) { - const newest = getNewestEventTagsByKey(pinnedFeed, "e"); - if (newest) { - setPinned(login, newest.keys, newest.createdAt * 1000); - } - } - - function handleTagFeed(tagFeed: TaggedNostrEvent[]) { - const newest = getNewestEventTagsByKey(tagFeed, "t"); - if (newest) { - setTags(login, newest.keys, newest.createdAt * 1000); - } - } - - function handleBookmarkFeed(bookmarkFeed: TaggedNostrEvent[]) { - const newest = getNewestEventTagsByKey(bookmarkFeed, "e"); - if (newest) { - setBookmarked(login, newest.keys, newest.createdAt * 1000); - } - } - - function handlePublicChatsListFeed(bookmarkFeed: TaggedNostrEvent[]) { - const newest = getNewestEventTagsByKey(bookmarkFeed, "e"); - if (newest) { - LoginStore.updateSession({ - ...login, - extraChats: newest.keys.map(Nip28ChatSystem.chatId), - }); - } - } + }, [login, loginFeed, publisher]); useEffect(() => { - if (loginFeed) { - const mutedFeed = loginFeed.filter(a => a.kind === EventKind.MuteList); - handleMutedFeed(mutedFeed); - - const pinnedFeed = loginFeed.filter(a => a.kind === EventKind.PinList); - handlePinnedFeed(pinnedFeed); - - const tagsFeed = loginFeed.filter(a => a.kind === EventKind.InterestsList); - handleTagFeed(tagsFeed); - - const bookmarkFeed = loginFeed.filter(a => a.kind === EventKind.BookmarksList); - handleBookmarkFeed(bookmarkFeed); - - const publicChatsFeed = loginFeed.filter(a => a.kind === EventKind.PublicChatsList); - handlePublicChatsListFeed(publicChatsFeed); - } - }, [loginFeed]); - - useEffect(() => { - const pTags = contacts.filter(a => a[0] === "p").map(a => a[1]); - system.profileLoader.TrackKeys(pTags); // always track follows profiles - }, [contacts]); + system.profileLoader.TrackKeys(login.state.follows ?? []); // always track follows profiles + }, [system, login.state.follows]); } diff --git a/packages/app/src/Feed/ThreadFeed.ts b/packages/app/src/Feed/ThreadFeed.ts index 95defbfd..1c52d9c7 100644 --- a/packages/app/src/Feed/ThreadFeed.ts +++ b/packages/app/src/Feed/ThreadFeed.ts @@ -1,4 +1,4 @@ -import { EventExt, EventKind, NostrLink, RequestBuilder } from "@snort/system"; +import { EventKind, Nip10, NostrLink, RequestBuilder } from "@snort/system"; import { SnortContext, useRequestBuilder } from "@snort/system-react"; import { useContext, useEffect, useMemo, useState } from "react"; @@ -39,7 +39,7 @@ export default function useThreadFeed(link: NostrLink) { .relay(rootRelays ?? []); } return sub; - }, [allEvents.length, rootRelays]); + }, [allEvents, link, root, rootRelays]); const store = useRequestBuilder(sub); @@ -53,27 +53,21 @@ export default function useThreadFeed(link: NostrLink) { .flat(); setAllEvents(links); + // load the thread structure from the current note const current = store.find(a => link.matchesEvent(a)); if (current) { - const t = EventExt.extractThread(current); + const t = Nip10.parseThread(current); if (t) { const rootOrReplyAsRoot = t?.root ?? t?.replyTo; if (rootOrReplyAsRoot) { - setRoot( - NostrLink.fromTag([ - rootOrReplyAsRoot.key, - rootOrReplyAsRoot.value ?? "", - rootOrReplyAsRoot.relay ?? "", - ...(rootOrReplyAsRoot.marker ?? []), - ]), - ); + setRoot(rootOrReplyAsRoot); } } else { setRoot(link); } } } - }, [store?.length]); + }, [link, store, store.length]); useEffect(() => { if (root) { @@ -87,12 +81,15 @@ export default function useThreadFeed(link: NostrLink) { relays.relays.filter(a => a.settings.read).map(a => a.url), 3, ); + if (root.relays) { + readRelays.push(...root.relays); + } setRootRelays(readRelays); } }); } } - }, [link, root, store?.length]); + }, [link, root, store, store.length, system.relayCache]); return store ?? []; } diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index a9478b4f..7846d18c 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -3,8 +3,8 @@ import { EventKind, RequestBuilder } from "@snort/system"; import { useRequestBuilderAdvanced } from "@snort/system-react"; import { useCallback, useMemo, useSyncExternalStore } from "react"; -import useLogin from "@/Hooks/useLogin"; import useModeration from "@/Hooks/useModeration"; +import usePreferences from "@/Hooks/usePreferences"; import useTimelineWindow from "@/Hooks/useTimelineWindow"; import { SearchRelays } from "@/Utils/Const"; @@ -30,7 +30,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel window: options.window, now: options.now ?? unixNow(), }); - const pref = useLogin(s => s.appData.json.preferences); + const autoShowLatest = usePreferences(s => s.autoShowLatest); const { isEventMuted } = useModeration(); const createBuilder = useCallback(() => { @@ -93,7 +93,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel } return rb; } - }, [until, since, options.method, pref, createBuilder]); + }, [until, since, options.method, createBuilder]); const mainQuery = useRequestBuilderAdvanced(sub); const main = useSyncExternalStore( @@ -108,7 +108,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel const subRealtime = useMemo(() => { const rb = createBuilder(); - if (rb && !pref.autoShowLatest && options.method !== "LIMIT_UNTIL") { + if (rb && !autoShowLatest && options.method !== "LIMIT_UNTIL") { rb.withOptions({ leaveOpen: true, }); @@ -118,7 +118,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel } return rb; } - }, [pref.autoShowLatest, createBuilder]); + }, [autoShowLatest, createBuilder]); const latestQuery = useRequestBuilderAdvanced(subRealtime); const latest = useSyncExternalStore( diff --git a/packages/app/src/Hooks/useFollowControls.ts b/packages/app/src/Hooks/useFollowControls.ts index ac67a08c..d90bead9 100644 --- a/packages/app/src/Hooks/useFollowControls.ts +++ b/packages/app/src/Hooks/useFollowControls.ts @@ -1,48 +1,32 @@ -import { DiffSyncTags, EventKind, NostrLink, NostrPrefix } from "@snort/system"; -import { useMemo } from "react"; +import { NostrLink } from "@snort/system"; -import useEventPublisher from "./useEventPublisher"; import useLogin from "./useLogin"; /** * Simple hook for adding / removing follows */ export default function useFollowsControls() { - const { publisher, system } = useEventPublisher(); - const { pubkey, contacts, relays } = useLogin(s => ({ - pubkey: s.publicKey, - contacts: s.contacts, - readonly: s.readonly, - relays: s.relays.item, - })); + const state = useLogin(s => s.state); - return useMemo(() => { - const link = new NostrLink(NostrPrefix.Event, "", EventKind.ContactList, pubkey); - const sync = new DiffSyncTags(link); - const content = JSON.stringify(relays); - return { - isFollowing: (pk: string) => { - return contacts.some(a => a[0] === "p" && a[1] === pk); - }, - addFollow: async (pk: Array) => { - sync.add(pk.map(a => ["p", a])); - if (publisher) { - await sync.persist(publisher.signer, system, content); - } - }, - removeFollow: async (pk: Array) => { - sync.remove(pk.map(a => ["p", a])); - if (publisher) { - await sync.persist(publisher.signer, system, content); - } - }, - setFollows: async (pk: Array) => { - sync.replace(pk.map(a => ["p", a])); - if (publisher) { - await sync.persist(publisher.signer, system, content); - } - }, - followList: contacts.filter(a => a[0] === "p").map(a => a[1]), - }; - }, [contacts, relays, publisher, system]); + return { + isFollowing: (pk: string) => { + return state.follows?.includes(pk); + }, + addFollow: async (pk: Array) => { + for (const p of pk) { + await state.follow(NostrLink.publicKey(p), false); + } + await state.saveContacts(); + }, + removeFollow: async (pk: Array) => { + for (const p of pk) { + await state.unfollow(NostrLink.publicKey(p), false); + } + await state.saveContacts(); + }, + setFollows: async (pk: Array) => { + await state.replaceFollows(pk.map(a => NostrLink.publicKey(a))); + }, + followList: state.follows ?? [], + }; } diff --git a/packages/app/src/Hooks/useImgProxy.ts b/packages/app/src/Hooks/useImgProxy.ts index af530e0d..b1596665 100644 --- a/packages/app/src/Hooks/useImgProxy.ts +++ b/packages/app/src/Hooks/useImgProxy.ts @@ -1,7 +1,7 @@ import * as utils from "@noble/curves/abstract/utils"; import { base64 } from "@scure/base"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { hmacSha256, unwrap } from "@/Utils"; export interface ImgProxySettings { @@ -11,10 +11,10 @@ export interface ImgProxySettings { } export default function useImgProxy() { - const settings = useLogin(s => s.appData.json.preferences.imgProxyConfig); + const imgProxyConfig = usePreferences(s => s.imgProxyConfig); return { - proxy: (url: string, resize?: number, sha256?: string) => proxyImg(url, settings, resize, sha256), + proxy: (url: string, resize?: number, sha256?: string) => proxyImg(url, imgProxyConfig, resize, sha256), }; } diff --git a/packages/app/src/Hooks/useLists.tsx b/packages/app/src/Hooks/useLists.tsx index d3815ea9..0398548e 100644 --- a/packages/app/src/Hooks/useLists.tsx +++ b/packages/app/src/Hooks/useLists.tsx @@ -36,14 +36,6 @@ export function usePinList(pubkey: string | undefined) { }); } -export function useMuteList(pubkey: string | undefined) { - return useLinkList(`list:mute:${pubkey?.slice(0, 12)}`, rb => { - if (pubkey) { - rb.withFilter().kinds([EventKind.MuteList]).authors([pubkey]); - } - }); -} - export function useBookmarkList(pubkey: string | undefined) { return useLinkListEvents(`list:bookmark:${pubkey?.slice(0, 12)}`, rb => { if (pubkey) { diff --git a/packages/app/src/Hooks/useLoginRelays.tsx b/packages/app/src/Hooks/useLoginRelays.tsx index 389b5f2a..a2df5b30 100644 --- a/packages/app/src/Hooks/useLoginRelays.tsx +++ b/packages/app/src/Hooks/useLoginRelays.tsx @@ -2,10 +2,10 @@ import { RelaySettings, SystemInterface } from "@snort/system"; import { useEffect } from "react"; import useEventPublisher from "./useEventPublisher"; -import useLogin from "./useLogin"; +import useRelays from "./useRelays"; export function useLoginRelays() { - const relays = useLogin(s => s.relays.item); + const relays = useRelays(); const { system } = useEventPublisher(); useEffect(() => { diff --git a/packages/app/src/Hooks/useModeration.tsx b/packages/app/src/Hooks/useModeration.tsx index b49820a9..f0b845f2 100644 --- a/packages/app/src/Hooks/useModeration.tsx +++ b/packages/app/src/Hooks/useModeration.tsx @@ -1,80 +1,48 @@ -import { HexKey, NostrEvent, TaggedNostrEvent } from "@snort/system"; +import { EventKind, NostrEvent, NostrLink, TaggedNostrEvent } from "@snort/system"; -import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; -import { appendDedupe } from "@/Utils"; -import { setBlocked, setMuted } from "@/Utils/Login"; +import { dedupe } from "@snort/shared"; export default function useModeration() { - const login = useLogin(); - const { muted, blocked, appData } = login; - const { publisher, system } = useEventPublisher(); + const state = useLogin(s => s.state); - async function setMutedList(pub: HexKey[], priv: HexKey[]) { - if (publisher) { - const ev = await publisher.muted(pub, priv); - system.BroadcastEvent(ev); - return ev.created_at * 1000; + function isMuted(id: string) { + const link = NostrLink.publicKey(id); + return state.muted.includes(link); + } + + async function unmute(id: string) { + const link = NostrLink.publicKey(id); + await state.unmute(link, true); + } + + async function mute(id: string) { + const link = NostrLink.publicKey(id); + await state.mute(link, true); + } + + async function muteAll(ids: string[]) { + const links = dedupe(ids).map(a => NostrLink.publicKey(a)); + for (const link of links) { + await state.mute(link, false); } - return 0; - } - - function isMuted(id: HexKey) { - return muted.item.includes(id) || blocked.item.includes(id); - } - - function isBlocked(id: HexKey) { - return blocked.item.includes(id); - } - - async function unmute(id: HexKey) { - const newMuted = muted.item.filter(p => p !== id); - const ts = await setMutedList(newMuted, blocked.item); - setMuted(login, newMuted, ts); - } - - async function unblock(id: HexKey) { - const newBlocked = blocked.item.filter(p => p !== id); - const ts = await setMutedList(muted.item, newBlocked); - setBlocked(login, newBlocked, ts); - } - - async function mute(id: HexKey) { - const newMuted = muted.item.includes(id) ? muted.item : muted.item.concat([id]); - const ts = await setMutedList(newMuted, blocked.item); - setMuted(login, newMuted, ts); - } - - async function block(id: HexKey) { - const newBlocked = blocked.item.includes(id) ? blocked.item : blocked.item.concat([id]); - const ts = await setMutedList(muted.item, newBlocked); - setBlocked(login, newBlocked, ts); - } - - async function muteAll(ids: HexKey[]) { - const newMuted = appendDedupe(muted.item, ids); - const ts = await setMutedList(newMuted, blocked.item); - setMuted(login, newMuted, ts); + await state.saveList(EventKind.MuteList); } function isMutedWord(word: string) { - return appData.json.mutedWords.includes(word.toLowerCase()); + return false; } function isEventMuted(ev: TaggedNostrEvent | NostrEvent) { - return isMuted(ev.pubkey) || appData.json.mutedWords.some(w => ev.content.toLowerCase().includes(w)); + return isMuted(ev.pubkey) || false; } return { - muted: muted.item, + muteList: state.muted, mute, muteAll, unmute, isMuted, - blocked: blocked.item, - block, - unblock, - isBlocked, isMutedWord, isEventMuted, }; diff --git a/packages/app/src/Hooks/usePreferences.ts b/packages/app/src/Hooks/usePreferences.ts index d654a340..f9e9b051 100644 --- a/packages/app/src/Hooks/usePreferences.ts +++ b/packages/app/src/Hooks/usePreferences.ts @@ -1,10 +1,32 @@ -import { updateAppData, UserPreferences } from "@/Utils/Login"; +import { DefaultPreferences, updateAppData, UserPreferences } from "@/Utils/Login"; import useEventPublisher from "./useEventPublisher"; import useLogin from "./useLogin"; -export default function usePreferences() { - const { id, pref } = useLogin(s => ({ id: s.id, pref: s.appData.json.preferences })); +export default function usePreferences(selector?: (v: UserPreferences) => T): T { + const defaultSelector = (v: UserPreferences) => v as unknown as T; + return useLogin(s => { + const pref = s.state.appdata?.preferences ?? { + ...DefaultPreferences, + ...CONFIG.defaultPreferences, + }; + + return (selector || defaultSelector)(pref); + }); +} + +export function useAllPreferences() { + const { id, pref } = useLogin(s => { + const pref = s.state.appdata?.preferences ?? { + ...DefaultPreferences, + ...CONFIG.defaultPreferences, + }; + + return { + id: s.id, + pref: pref, + }; + }); const { system } = useEventPublisher(); return { diff --git a/packages/app/src/Hooks/useProfileSearch.tsx b/packages/app/src/Hooks/useProfileSearch.tsx index 40d307e4..3e3350ba 100644 --- a/packages/app/src/Hooks/useProfileSearch.tsx +++ b/packages/app/src/Hooks/useProfileSearch.tsx @@ -2,10 +2,10 @@ import { socialGraphInstance } from "@snort/system"; import { useEffect, useMemo, useState } from "react"; import fuzzySearch from "@/Db/FuzzySearch"; -import useTimelineFeed from "@/Feed/TimelineFeed"; +import useTimelineFeed, { TimelineFeedOptions, TimelineSubject } from "@/Feed/TimelineFeed"; import { debounce } from "@/Utils"; -const options = { method: "LIMIT_UNTIL" }; +const options: TimelineFeedOptions = { method: "LIMIT_UNTIL" }; export default function useProfileSearch(search: string) { const [debouncedSearch, setDebouncedSearch] = useState(search); @@ -17,11 +17,12 @@ export default function useProfileSearch(search: string) { }, [search]); const subject = useMemo( - () => ({ - type: "profile_keyword", - items: debouncedSearch ? [debouncedSearch] : [], - discriminator: debouncedSearch, - }), + () => + ({ + type: "profile_keyword", + items: debouncedSearch ? [debouncedSearch] : [], + discriminator: debouncedSearch, + }) as TimelineSubject, [debouncedSearch], ); const feed = useTimelineFeed(subject, options); diff --git a/packages/app/src/Hooks/useRelays.tsx b/packages/app/src/Hooks/useRelays.tsx new file mode 100644 index 00000000..14eeb11a --- /dev/null +++ b/packages/app/src/Hooks/useRelays.tsx @@ -0,0 +1,6 @@ +import useLogin from "./useLogin"; + +export default function useRelays() { + const relays = useLogin(s => s.state.relays); + return relays ? Object.fromEntries(relays.map(a => [a.url, a.settings])) : CONFIG.defaultRelays; +} diff --git a/packages/app/src/Hooks/useTheme.tsx b/packages/app/src/Hooks/useTheme.tsx index 5ff605bc..90720eab 100644 --- a/packages/app/src/Hooks/useTheme.tsx +++ b/packages/app/src/Hooks/useTheme.tsx @@ -1,9 +1,9 @@ import { useEffect } from "react"; -import useLogin from "./useLogin"; +import usePreferences from "./usePreferences"; export function useTheme() { - const { preferences } = useLogin(s => ({ preferences: s.appData.json.preferences })); + const theme = usePreferences(s => s.theme); function setTheme(theme: "light" | "dark") { const elm = document.documentElement; @@ -16,17 +16,15 @@ export function useTheme() { useEffect(() => { const osTheme = window.matchMedia("(prefers-color-scheme: light)"); - setTheme( - preferences.theme === "system" && osTheme.matches ? "light" : preferences.theme === "light" ? "light" : "dark", - ); + setTheme(theme === "system" && osTheme.matches ? "light" : theme === "light" ? "light" : "dark"); osTheme.onchange = e => { - if (preferences.theme === "system") { + if (theme === "system") { setTheme(e.matches ? "light" : "dark"); } }; return () => { osTheme.onchange = null; }; - }, [preferences.theme]); + }, [theme]); } diff --git a/packages/app/src/Pages/Deck/DeckLayout.tsx b/packages/app/src/Pages/Deck/DeckLayout.tsx index 63c18a68..37b12726 100644 --- a/packages/app/src/Pages/Deck/DeckLayout.tsx +++ b/packages/app/src/Pages/Deck/DeckLayout.tsx @@ -13,6 +13,7 @@ import Toaster from "@/Components/Toaster/Toaster"; import useLoginFeed from "@/Feed/LoginFeed"; import useLogin from "@/Hooks/useLogin"; import { useLoginRelays } from "@/Hooks/useLoginRelays"; +import usePreferences from "@/Hooks/usePreferences"; import { useTheme } from "@/Hooks/useTheme"; import { ArticlesCol, MediaCol, NotesCol, NotificationsCol } from "@/Pages/Deck/Columns"; import NavSidebar from "@/Pages/Layout/NavSidebar"; @@ -40,8 +41,8 @@ export function SnortDeckLayout() { const login = useLogin(s => ({ publicKey: s.publicKey, subscriptions: s.subscriptions, - telemetry: s.appData.json.preferences.telemetry, })); + const telemetry = usePreferences(s => s.telemetry); const navigate = useNavigate(); const [deckState, setDeckState] = useState({ thread: undefined, @@ -60,7 +61,7 @@ export function SnortDeckLayout() { }, [login]); useEffect(() => { - if (CONFIG.features.analytics && (login.telemetry ?? true)) { + if (CONFIG.features.analytics && (telemetry ?? true)) { trackEvent("pageview"); } }, [location]); diff --git a/packages/app/src/Pages/HashTagsPage.tsx b/packages/app/src/Pages/HashTagsPage.tsx index 4b630a8d..1d8942a9 100644 --- a/packages/app/src/Pages/HashTagsPage.tsx +++ b/packages/app/src/Pages/HashTagsPage.tsx @@ -1,5 +1,5 @@ import { dedupe } from "@snort/shared"; -import { EventKind, RequestBuilder } from "@snort/system"; +import { EventKind, NostrHashtagLink, RequestBuilder } from "@snort/system"; import { useRequestBuilder } from "@snort/system-react"; import classNames from "classnames"; import { useMemo } from "react"; @@ -9,15 +9,22 @@ import { Link, useParams } from "react-router-dom"; import AsyncButton from "@/Components/Button/AsyncButton"; import Timeline from "@/Components/Feed/Timeline"; import ProfileImage from "@/Components/User/ProfileImage"; -import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; -import { setTags } from "@/Utils/Login"; import { formatShort } from "@/Utils/Number"; +import { TimelineSubject } from "@/Feed/TimelineFeed"; const HashTagsPage = () => { const params = useParams(); const tag = (params.tag ?? "").toLowerCase(); - const subject = useMemo(() => ({ type: "hashtag", items: [tag], discriminator: tag }), [tag]); + const subject = useMemo( + () => + ({ + type: "hashtag", + items: [tag], + discriminator: tag, + }) as TimelineSubject, + [tag], + ); return ( <> @@ -32,23 +39,10 @@ const HashTagsPage = () => { export default HashTagsPage; export function HashTagHeader({ tag, events, className }: { tag: string; events?: number; className?: string }) { - const login = useLogin(); + const state = useLogin(s => s.state); const isFollowing = useMemo(() => { - return login.tags.item.includes(tag); - }, [login, tag]); - const { publisher, system } = useEventPublisher(); - - async function followTags(ts: string[]) { - if (publisher) { - const ev = await publisher.generic(eb => { - eb.kind(EventKind.InterestsList); - ts.forEach(a => eb.tag(["t", a])); - return eb; - }); - setTags(login, ts, ev.created_at * 1000); - await system.BroadcastEvent(ev); - } - } + return state.isOnList(EventKind.InterestsList, new NostrHashtagLink(tag)); + }, [state, tag]); const sub = useMemo(() => { const rb = new RequestBuilder(`hashtag-counts:${tag}`); @@ -78,11 +72,13 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events? )}
{isFollowing ? ( - followTags(login.tags.item.filter(t => t !== tag))}> + state.removeFromList(EventKind.InterestsList, new NostrHashtagLink(tag), true)}> ) : ( - followTags(login.tags.item.concat([tag]))}> + state.addToList(EventKind.InterestsList, new NostrHashtagLink(tag), true)}> )} diff --git a/packages/app/src/Pages/Layout/Header.tsx b/packages/app/src/Pages/Layout/Header.tsx index 66331cc0..fbf4a094 100644 --- a/packages/app/src/Pages/Layout/Header.tsx +++ b/packages/app/src/Pages/Layout/Header.tsx @@ -1,4 +1,4 @@ -import { NostrLink, NostrPrefix, parseNostrLink } from "@snort/system"; +import { EventKind, NostrLink, NostrPrefix, parseNostrLink } from "@snort/system"; import { useEventFeed } from "@snort/system-react"; import classNames from "classnames"; import React, { useCallback, useMemo } from "react"; @@ -13,6 +13,7 @@ import useLogin from "@/Hooks/useLogin"; import { LogoHeader } from "@/Pages/Layout/LogoHeader"; import NotificationsHeader from "@/Pages/Layout/NotificationsHeader"; import { bech32ToHex } from "@/Utils"; +import { unwrap } from "@snort/shared"; export function Header() { const navigate = useNavigate(); @@ -27,10 +28,17 @@ export function Header() { } }, [pageName]); - const { publicKey, tags } = useLogin(); + const { publicKey, tags } = useLogin(s => ({ + publicKey: s.publicKey, + tags: s.state.getList(EventKind.InterestsList), + })); const isRootTab = useMemo(() => { - return location.pathname === "/" || rootTabItems("", publicKey, tags).some(item => item.path === location.pathname); + // todo: clean this up, its also in other places + const hashTags = tags.filter(a => a.toEventTag()?.[0] === "t").map(a => unwrap(a.toEventTag())[1]); + return ( + location.pathname === "/" || rootTabItems("", publicKey, hashTags).some(item => item.path === location.pathname) + ); }, [location.pathname, publicKey, tags]); const scrollUp = useCallback(() => { diff --git a/packages/app/src/Pages/Layout/index.tsx b/packages/app/src/Pages/Layout/index.tsx index 87f22403..58a91920 100644 --- a/packages/app/src/Pages/Layout/index.tsx +++ b/packages/app/src/Pages/Layout/index.tsx @@ -13,6 +13,7 @@ import { useCommunityLeaders } from "@/Hooks/useCommunityLeaders"; import useKeyboardShortcut from "@/Hooks/useKeyboardShortcut"; import useLogin from "@/Hooks/useLogin"; import { useLoginRelays } from "@/Hooks/useLoginRelays"; +import usePreferences from "@/Hooks/usePreferences"; import { useTheme } from "@/Hooks/useTheme"; import Footer from "@/Pages/Layout/Footer"; import { Header } from "@/Pages/Layout/Header"; @@ -24,11 +25,11 @@ import RightColumn from "./RightColumn"; export default function Index() { const location = useLocation(); - const { id, stalker, telemetry } = useLogin(s => ({ + const { id, stalker } = useLogin(s => ({ id: s.id, stalker: s.stalker ?? false, - telemetry: s.appData.json.preferences.telemetry, })); + const telemetry = usePreferences(s => s.telemetry); useTheme(); useLoginRelays(); diff --git a/packages/app/src/Pages/NetworkGraph/Avatar.tsx b/packages/app/src/Pages/NetworkGraph/Avatar.tsx index cacde43a..320d87b7 100644 --- a/packages/app/src/Pages/NetworkGraph/Avatar.tsx +++ b/packages/app/src/Pages/NetworkGraph/Avatar.tsx @@ -8,6 +8,6 @@ import { LoginStore } from "@/Utils/Login"; export const avatar = (node: NodeObject>) => { const login = LoginStore.snapshot(); return node.profile?.picture - ? proxyImg(node.profile?.picture, login.appData.json.preferences.imgProxyConfig) + ? proxyImg(node.profile?.picture, login.state.appdata?.preferences.imgProxyConfig) : defaultAvatar(node.address); }; diff --git a/packages/app/src/Pages/Notifications/getNotificationContext.tsx b/packages/app/src/Pages/Notifications/getNotificationContext.tsx index 6e2f7c5d..f93497fe 100644 --- a/packages/app/src/Pages/Notifications/getNotificationContext.tsx +++ b/packages/app/src/Pages/Notifications/getNotificationContext.tsx @@ -1,5 +1,4 @@ -import { unwrap } from "@snort/shared"; -import { EventExt, EventKind, NostrLink, TaggedNostrEvent } from "@snort/system"; +import { EventKind, NostrLink, TaggedNostrEvent, Nip10 } from "@snort/system"; export function getNotificationContext(ev: TaggedNostrEvent) { switch (ev.kind) { @@ -20,10 +19,10 @@ export function getNotificationContext(ev: TaggedNostrEvent) { } case EventKind.Repost: case EventKind.Reaction: { - const thread = EventExt.extractThread(ev); - const tag = unwrap(thread?.replyTo ?? thread?.root ?? { value: ev.id, key: "e" }); - if (tag.key === "e" || tag.key === "a") { - return NostrLink.fromThreadTag(tag); + const thread = Nip10.parseThread(ev); + const tag = thread?.replyTo ?? thread?.root; + if (tag) { + return tag; } else { throw new Error("Unknown thread context"); } diff --git a/packages/app/src/Pages/Profile/ProfileDetails.tsx b/packages/app/src/Pages/Profile/ProfileDetails.tsx index 7fc4740a..a0afa3ac 100644 --- a/packages/app/src/Pages/Profile/ProfileDetails.tsx +++ b/packages/app/src/Pages/Profile/ProfileDetails.tsx @@ -13,7 +13,7 @@ import { UserWebsiteLink } from "@/Components/User/UserWebsiteLink"; import ZapModal from "@/Components/ZapModal/ZapModal"; import useProfileBadges from "@/Feed/BadgesFeed"; import useFollowsFeed from "@/Feed/FollowsFeed"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { MusicStatus } from "@/Pages/Profile/MusicStatus"; const ProfileDetails = ({ @@ -31,9 +31,9 @@ const ProfileDetails = ({ lnurl?: LNURL; }) => { const follows = useFollowsFeed(id); - const { showStatus, showBadges } = useLogin(s => ({ - showStatus: s.appData.json.preferences.showStatus ?? false, - showBadges: s.appData.json.preferences.showBadges ?? false, + const { showStatus, showBadges } = usePreferences(s => ({ + showStatus: s.showStatus ?? false, + showBadges: s.showBadges ?? false, })); const [showLnQr, setShowLnQr] = useState(false); const badges = useProfileBadges(showBadges ? id : undefined); diff --git a/packages/app/src/Pages/Profile/ProfilePage.tsx b/packages/app/src/Pages/Profile/ProfilePage.tsx index d93cb653..c5dc9f73 100644 --- a/packages/app/src/Pages/Profile/ProfilePage.tsx +++ b/packages/app/src/Pages/Profile/ProfilePage.tsx @@ -9,14 +9,11 @@ import { useLocation, useNavigate, useParams } from "react-router-dom"; import { ProxyImg } from "@/Components/ProxyImg"; import { SpotlightMediaModal } from "@/Components/Spotlight/SpotlightMedia"; import { Tab, TabSelector } from "@/Components/TabSelectors/TabSelectors"; -import BlockList from "@/Components/User/BlockList"; import FollowsList from "@/Components/User/FollowListBase"; import MutedList from "@/Components/User/MutedList"; import useFollowsFeed from "@/Feed/FollowsFeed"; import useHorizontalScroll from "@/Hooks/useHorizontalScroll"; -import { useMuteList } from "@/Hooks/useLists"; import useLogin from "@/Hooks/useLogin"; -import useModeration from "@/Hooks/useModeration"; import AvatarSection from "@/Pages/Profile/AvatarSection"; import ProfileDetails from "@/Pages/Profile/ProfileDetails"; import { @@ -63,18 +60,13 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) { }, [user]); // feeds - const { blocked } = useModeration(); - const muted = useMuteList(id); const follows = useFollowsFeed(id); // tabs const [tab, setTab] = useState(ProfileTabSelectors.Notes); - const optionalTabs = [ - ProfileTabSelectors.Zaps, - ProfileTabSelectors.Relays, - ProfileTabSelectors.Bookmarks, - ProfileTabSelectors.Muted, - ].filter(a => unwrap(a)) as Tab[]; + const optionalTabs = [ProfileTabSelectors.Zaps, ProfileTabSelectors.Relays, ProfileTabSelectors.Bookmarks].filter(a => + unwrap(a), + ) as Tab[]; const horizontalScroll = useHorizontalScroll(); useEffect(() => { @@ -128,12 +120,6 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) { case ProfileTabType.FOLLOWERS: { return ; } - case ProfileTabType.MUTED: { - return a.id)} />; - } - case ProfileTabType.BLOCKED: { - return ; - } case ProfileTabType.RELAYS: { return ; } @@ -143,6 +129,9 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) { case ProfileTabType.REACTIONS: { return ; } + case ProfileTabType.MUTED: { + return ; + } } } @@ -186,7 +175,7 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) { ProfileTabSelectors.Follows, ].map(renderTabSelector)} {optionalTabs.map(renderTabSelector)} - {isMe && blocked.length > 0 && renderTabSelector(ProfileTabSelectors.Blocked)} + {isMe && renderTabSelector(ProfileTabSelectors.Muted)}
{tabContent()}
diff --git a/packages/app/src/Pages/Profile/ProfileTabType.tsx b/packages/app/src/Pages/Profile/ProfileTabType.tsx index 08b1340a..f3c525b8 100644 --- a/packages/app/src/Pages/Profile/ProfileTabType.tsx +++ b/packages/app/src/Pages/Profile/ProfileTabType.tsx @@ -5,7 +5,6 @@ export enum ProfileTabType { FOLLOWS = 3, ZAPS = 4, MUTED = 5, - BLOCKED = 6, RELAYS = 7, BOOKMARKS = 8, } diff --git a/packages/app/src/Pages/Root/DefaultTab.tsx b/packages/app/src/Pages/Root/DefaultTab.tsx index 07f4efdf..84f18bd8 100644 --- a/packages/app/src/Pages/Root/DefaultTab.tsx +++ b/packages/app/src/Pages/Root/DefaultTab.tsx @@ -1,12 +1,13 @@ import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes"; export const DefaultTab = () => { - const { preferences, publicKey } = useLogin(s => ({ - preferences: s.appData.json.preferences, + const { publicKey } = useLogin(s => ({ publicKey: s.publicKey, })); - const tab = publicKey ? preferences.defaultRootTab : `trending/notes`; + const defaultRootTab = usePreferences(s => s.defaultRootTab); + const tab = publicKey ? defaultRootTab : `trending/notes`; const elm = RootTabRoutes.find(a => a.path === tab)?.element; - return elm ?? RootTabRoutes.find(a => a.path === preferences.defaultRootTab)?.element; + return elm ?? RootTabRoutes.find(a => a.path === defaultRootTab)?.element; }; diff --git a/packages/app/src/Pages/Root/ForYouTab.tsx b/packages/app/src/Pages/Root/ForYouTab.tsx index 3aa4d00d..7d324f2a 100644 --- a/packages/app/src/Pages/Root/ForYouTab.tsx +++ b/packages/app/src/Pages/Root/ForYouTab.tsx @@ -15,8 +15,9 @@ import messages from "@/Pages/messages"; import { System } from "@/system"; const FollowsHint = () => { - const { publicKey, contacts } = useLogin(); - if (contacts.length === 0 && publicKey) { + const publicKey = useLogin(s => s.publicKey); + const { followList } = useFollowsControls(); + if (followList.length === 0 && publicKey) { return ( { /> ); } - return null; }; let forYouFeed = { @@ -62,7 +62,11 @@ const getReactedByFollows = (follows: string[]) => { export const ForYouTab = memo(function ForYouTab() { const [notes, setNotes] = useState(forYouFeed.events); - const login = useLogin(); + const login = useLogin(s => ({ + feedDisplayAs: s.feedDisplayAs, + publicKey: s.publicKey, + tags: s.state.getList(EventKind.InterestSet), + })); const displayAsInitial = login.feedDisplayAs ?? "list"; const [displayAs, setDisplayAs] = useState(displayAsInitial); const navigationType = useNavigationType(); @@ -82,12 +86,12 @@ export const ForYouTab = memo(function ForYouTab() { items: followList, discriminator: login.publicKey?.slice(0, 12), extra: rb => { - if (login.tags.item.length > 0) { - rb.withFilter().kinds([EventKind.TextNote]).tag("t", login.tags.item); + if (login.tags.length > 0) { + rb.withFilter().kinds([EventKind.TextNote]).tags(login.tags); } }, }) as TimelineSubject, - [followList, login.tags.item], + [login.publicKey, followList, login.tags], ); // also get "follows" feed so data is loaded from relays and there's a fallback if "for you" feed is empty const latestFeed = useTimelineFeed(subject, { method: "TIME_RANGE", now: openedAt } as TimelineFeedOptions); @@ -164,7 +168,7 @@ export const ForYouTab = memo(function ForYouTab() { const frags = useMemo(() => { return [ { - events: combinedFeed, + events: combinedFeed as Array, refTime: Date.now(), }, ]; @@ -175,7 +179,13 @@ export const ForYouTab = memo(function ForYouTab() { setDisplayAs(a)} /> - latestFeed.loadMore()} /> + latestFeed.loadMore()} + showLatest={() => {}} + /> ); }); diff --git a/packages/app/src/Pages/Root/NotesTab.tsx b/packages/app/src/Pages/Root/NotesTab.tsx index 63a2482d..4ffef5b9 100644 --- a/packages/app/src/Pages/Root/NotesTab.tsx +++ b/packages/app/src/Pages/Root/NotesTab.tsx @@ -1,17 +1,19 @@ -import { NostrLink } from "@snort/system"; +import { NostrEvent, NostrLink } from "@snort/system"; import { useContext, useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { Link } from "react-router-dom"; import TimelineFollows from "@/Components/Feed/TimelineFollows"; import { TaskList } from "@/Components/Tasks/TaskList"; +import useFollowsControls from "@/Hooks/useFollowControls"; import useLogin from "@/Hooks/useLogin"; import { DeckContext } from "@/Pages/Deck/DeckLayout"; import messages from "@/Pages/messages"; const FollowsHint = () => { - const { publicKey: pubKey, follows } = useLogin(); - if (follows.item?.length === 0 && pubKey) { + const publicKey = useLogin(s => s.publicKey); + const { followList } = useFollowsControls(); + if (followList.length === 0 && publicKey) { return ( { /> ); } - return null; }; + export const NotesTab = () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const deckContext = useContext(DeckContext); const noteOnClick = useMemo(() => { if (deckContext) { - return ev => { + return (ev: NostrEvent) => { deckContext.setThread(NostrLink.fromEvent(ev)); }; } diff --git a/packages/app/src/Pages/TopicsPage.tsx b/packages/app/src/Pages/TopicsPage.tsx index 5ed56d04..c8db1a0e 100644 --- a/packages/app/src/Pages/TopicsPage.tsx +++ b/packages/app/src/Pages/TopicsPage.tsx @@ -2,15 +2,22 @@ import { useMemo } from "react"; import Timeline from "@/Components/Feed/Timeline"; import useLogin from "@/Hooks/useLogin"; +import { EventKind } from "@snort/system"; +import { unwrap } from "@snort/shared"; +import { TimelineSubject } from "@/Feed/TimelineFeed"; export function TopicsPage() { - const { tags, pubKey } = useLogin(s => ({ tags: s.tags.item, pubKey: s.publicKey })); + const { tags, pubKey } = useLogin(s => ({ + pubKey: s.publicKey, + tags: s.state.getList(EventKind.InterestSet), + })); const subject = useMemo( - () => ({ - type: "hashtag", - items: tags, - discriminator: pubKey ?? "", - }), + () => + ({ + type: "hashtag", + items: tags.filter(a => a.toEventTag()?.[0] === "t").map(a => unwrap(a.toEventTag())[1]), + discriminator: pubKey ?? "", + }) as TimelineSubject, [tags, pubKey], ); diff --git a/packages/app/src/Pages/ZapPool/ZapPoolPageInner.tsx b/packages/app/src/Pages/ZapPool/ZapPoolPageInner.tsx index 7bafb26f..60c92589 100644 --- a/packages/app/src/Pages/ZapPool/ZapPoolPageInner.tsx +++ b/packages/app/src/Pages/ZapPool/ZapPoolPageInner.tsx @@ -1,9 +1,9 @@ -import { useMemo, useSyncExternalStore } from "react"; +import { SnortContext } from "@snort/system-react"; +import { useContext, useMemo, useSyncExternalStore } from "react"; import { FormattedMessage, FormattedNumber } from "react-intl"; import AsyncButton from "@/Components/Button/AsyncButton"; -import useEventPublisher from "@/Hooks/useEventPublisher"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { ZapPoolTarget } from "@/Pages/ZapPool/ZapPoolTarget"; import { bech32ToHex, getRelayName, trackEvent, unwrap } from "@/Utils"; import { SnortPubKey } from "@/Utils/Const"; @@ -19,8 +19,8 @@ const DataProviders = [ ]; export function ZapPoolPageInner() { - const login = useLogin(); - const { system } = useEventPublisher(); + const defaultZapAmount = usePreferences(s => s.defaultZapAmount); + const system = useContext(SnortContext); const zapPool = useSyncExternalStore( c => unwrap(ZapPoolController).hook(c), () => unwrap(ZapPoolController).snapshot(), @@ -39,7 +39,7 @@ export function ZapPoolPageInner() { }) .filter(a => a !== undefined) .map(unwrap); - }, [login.relays]); + }, []); const sumPending = zapPool.reduce((acc, v) => acc + v.sum, 0); return ( @@ -66,7 +66,7 @@ export function ZapPoolPageInner() { values={{ number: ( - + ), }} @@ -79,14 +79,12 @@ export function ZapPoolPageInner() { values={{ nIn: ( - + ), nOut: ( - + ), }} diff --git a/packages/app/src/Pages/ZapPool/ZapPoolTarget.tsx b/packages/app/src/Pages/ZapPool/ZapPoolTarget.tsx index e4fe5c5d..b1e7eddc 100644 --- a/packages/app/src/Pages/ZapPool/ZapPoolTarget.tsx +++ b/packages/app/src/Pages/ZapPool/ZapPoolTarget.tsx @@ -2,14 +2,13 @@ import { useUserProfile } from "@snort/system-react"; import { FormattedMessage, FormattedNumber } from "react-intl"; import ProfilePreview from "@/Components/User/ProfilePreview"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { ZapPoolController, ZapPoolRecipient } from "@/Utils/ZapPoolController"; function ZapPoolTargetInner({ target }: { target: ZapPoolRecipient }) { - const login = useLogin(); const profile = useUserProfile(target.pubkey); const hasAddress = profile?.lud16 || profile?.lud06; - const defaultZapMount = Math.ceil(login.appData.json.preferences.defaultZapAmount * (target.split / 100)); + const defaultZapMount = usePreferences(s => s.defaultZapAmount * (target.split / 100)); return ( ({ + updateAppData(login.id, ad => ({ ...ad, mutedWords: appendDedupe(appData.mutedWords, [muteWord]), })); @@ -21,14 +20,14 @@ export default function ModerationSettingsPage() { } const handleToggle = (setting: keyof SnortAppData) => { - updateAppData(login.id, system, ad => ({ + updateAppData(login.id, ad => ({ ...ad, [setting]: !appData[setting], })); }; function removeMutedWord(word: string) { - updateAppData(login.id, system, ad => ({ + updateAppData(login.id, ad => ({ ...ad, mutedWords: appData.mutedWords.filter(a => a !== word), })); diff --git a/packages/app/src/Pages/settings/Preferences.tsx b/packages/app/src/Pages/settings/Preferences.tsx index 5cf87e4f..8d9610e9 100644 --- a/packages/app/src/Pages/settings/Preferences.tsx +++ b/packages/app/src/Pages/settings/Preferences.tsx @@ -7,7 +7,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import AsyncButton from "@/Components/Button/AsyncButton"; import { AllLanguageCodes } from "@/Components/IntlProvider/IntlProviderUtils"; import { useLocale } from "@/Components/IntlProvider/useLocale"; -import usePreferences from "@/Hooks/usePreferences"; +import { useAllPreferences } from "@/Hooks/usePreferences"; import { unwrap } from "@/Utils"; import { DefaultImgProxy } from "@/Utils/Const"; import { UserPreferences } from "@/Utils/Login"; @@ -16,7 +16,7 @@ import messages from "./messages"; const PreferencesPage = () => { const { formatMessage } = useIntl(); - const { preferences, update: updatePerf } = usePreferences(); + const { preferences, update: updatePerf } = useAllPreferences(); const [pref, setPref] = useState(preferences); const [error, setError] = useState(""); const { lang } = useLocale(); diff --git a/packages/app/src/Pages/settings/RelayInfo.tsx b/packages/app/src/Pages/settings/RelayInfo.tsx index 3b9bf620..ad0e6ae5 100644 --- a/packages/app/src/Pages/settings/RelayInfo.tsx +++ b/packages/app/src/Pages/settings/RelayInfo.tsx @@ -1,12 +1,12 @@ import { FormattedMessage } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; +import AsyncButton from "@/Components/Button/AsyncButton"; import ProfilePreview from "@/Components/User/ProfilePreview"; import useRelayState from "@/Feed/RelayState"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; import { parseId, unwrap } from "@/Utils"; -import { removeRelay } from "@/Utils/Login"; import messages from "./messages"; @@ -104,14 +104,13 @@ const RelayInfo = () => { ))}
-
{ - removeRelay(login, unwrap(conn).Address); + { + await login.state.removeRelay(unwrap(conn).Address, true); navigate("/settings/relays"); }}> -
+
diff --git a/packages/app/src/Pages/settings/Relays.tsx b/packages/app/src/Pages/settings/Relays.tsx index 43ea43bf..d1f7c161 100644 --- a/packages/app/src/Pages/settings/Relays.tsx +++ b/packages/app/src/Pages/settings/Relays.tsx @@ -1,4 +1,4 @@ -import { unixNowMs, unwrap } from "@snort/shared"; +import { unwrap } from "@snort/shared"; import { useEffect, useMemo, useState } from "react"; import { FormattedMessage } from "react-intl"; @@ -7,31 +7,37 @@ import Relay from "@/Components/Relay/Relay"; import SnortApi, { RelayDistance } from "@/External/SnortApi"; import useEventPublisher from "@/Hooks/useEventPublisher"; import useLogin from "@/Hooks/useLogin"; +import useRelays from "@/Hooks/useRelays"; import { saveRelays } from "@/Pages/settings/saveRelays"; import { getCountry, getRelayName, sanitizeRelayUrl } from "@/Utils"; -import { setRelays } from "@/Utils/Login"; import { formatShort } from "@/Utils/Number"; import messages from "./messages"; const RelaySettingsPage = () => { const { publisher, system } = useEventPublisher(); - const login = useLogin(); - const relays = login.relays; + const relays = useRelays(); + const { readonly, state } = useLogin(s => ({ state: s.state, readonly: s.readonly })); const [newRelay, setNewRelay] = useState(); const otherConnections = useMemo(() => { - return [...system.pool].filter(([k]) => relays.item[k] === undefined).map(([, v]) => v); - }, [relays]); + return [...system.pool].filter(([k]) => relays[k] === undefined).map(([, v]) => v); + }, [system.pool, relays]); const handleNewRelayChange = (event: React.ChangeEvent) => { const inputValue = event.target.value; - const protocol = window.location.protocol; - if ((protocol === "https:" && inputValue.startsWith("wss://")) || protocol === "http:") { - setNewRelay(inputValue); - } + setNewRelay(inputValue); }; + async function addNewRelay() { + const url = sanitizeRelayUrl(newRelay); + if (url) { + await state.addRelay(url, { read: true, write: true }, false); + + setNewRelay(""); + } + } + function addRelay() { return (
@@ -45,35 +51,24 @@ const RelaySettingsPage = () => { value={newRelay} onChange={handleNewRelayChange} /> - +
); } - function addNewRelay() { - if ((newRelay?.length ?? 0) > 0) { - const parsed = new URL(newRelay ?? ""); - const payload = { - ...relays.item, - [parsed.toString()]: { read: true, write: true }, - }; - setRelays(login, payload, unixNowMs()); - } - } - return (

- {Object.keys(relays.item || {}).map(a => ( + {Object.keys(relays || {}).map(a => ( ))}
- saveRelays(system, publisher, relays.item)} disabled={login.readonly}> + saveRelays(system, publisher, relays.item)} disabled={readonly}> {addRelay()} @@ -96,14 +91,22 @@ export function CloseRelays() { const [relays, setRecommendedRelays] = useState>(); const country = getCountry(); const [location, setLocation] = useState<{ lat: number; lon: number }>(country); - const login = useLogin(); - const relayUrls = Object.keys(login.relays.item); + const currentRelays = useRelays(); + const state = useLogin(s => s.state); + const relayUrls = Object.keys(currentRelays); async function loadRelays() { const api = new SnortApi(); setRecommendedRelays(await api.closeRelays(location.lat, location.lon, 10)); } + async function addNewRelay(newRelay: string) { + const url = sanitizeRelayUrl(newRelay); + if (url) { + await state.addRelay(url, { read: true, write: true }, false); + } + } + useEffect(() => { loadRelays().catch(console.error); }, [location]); @@ -138,17 +141,7 @@ export function CloseRelays() {
{getRelayName(a.url)}
- { - setRelays( - login, - { - ...login.relays.item, - [a.url]: { read: true, write: true }, - }, - unixNowMs(), - ); - }}> + addNewRelay(a.url)}>
diff --git a/packages/app/src/Pages/settings/tools/prune-follows.tsx b/packages/app/src/Pages/settings/tools/prune-follows.tsx index ae565e3e..b9a67f58 100644 --- a/packages/app/src/Pages/settings/tools/prune-follows.tsx +++ b/packages/app/src/Pages/settings/tools/prune-follows.tsx @@ -17,14 +17,13 @@ const enum PruneStage { } export function PruneFollowList() { - const { followList: follows } = useFollowsControls(); + const followControls = useFollowsControls(); const { system } = useEventPublisher(); - const uniqueFollows = dedupe(follows); + const uniqueFollows = dedupe(followControls.followList); const [status, setStatus] = useState(); const [progress, setProgress] = useState(0); const [lastPost, setLastPosts] = useState>(); const [unfollow, setUnfollow] = useState>([]); - const followControls = useFollowsControls(); async function fetchLastPosts() { setStatus(PruneStage.FetchLastPostTimestamp); @@ -121,8 +120,8 @@ export function PruneFollowList() { defaultMessage="{x} follows ({y} duplicates)" id="iICVoL" values={{ - x: follows.length, - y: follows.length - uniqueFollows.length, + x: followControls.followList.length, + y: followControls.followList.length - uniqueFollows.length, }} />
diff --git a/packages/app/src/Pages/settings/tools/sync-account.tsx b/packages/app/src/Pages/settings/tools/sync-account.tsx index aa27b1e0..7785c105 100644 --- a/packages/app/src/Pages/settings/tools/sync-account.tsx +++ b/packages/app/src/Pages/settings/tools/sync-account.tsx @@ -6,6 +6,7 @@ import { FormattedMessage, FormattedNumber } from "react-intl"; import AsyncButton from "@/Components/Button/AsyncButton"; import useLogin from "@/Hooks/useLogin"; +import useRelays from "@/Hooks/useRelays"; import { SearchRelays } from "@/Utils/Const"; export default function SyncAccountTool() { @@ -13,9 +14,10 @@ export default function SyncAccountTool() { const login = useLogin(); const [scan, setScan] = useState(); const [results, setResults] = useState>([]); + const myRelays = useRelays(); async function start() { - const relays = Object.entries(login.relays.item) + const relays = Object.entries(myRelays) .filter(([, v]) => v.write) .map(([k]) => k); const sync = new RangeSync(system); diff --git a/packages/app/src/Utils/Login/Functions.ts b/packages/app/src/Utils/Login/Functions.ts index 5363c250..ab833067 100644 --- a/packages/app/src/Utils/Login/Functions.ts +++ b/packages/app/src/Utils/Login/Functions.ts @@ -22,40 +22,6 @@ import { SubscriptionEvent } from "@/Utils/Subscription"; import { Nip7OsSigner } from "./Nip7OsSigner"; -export function setRelays(state: LoginSession, relays: Record, createdAt: number) { - if (import.meta.env.VITE_SINGLE_RELAY) { - state.relays.item = { - [import.meta.env.VITE_SINGLE_RELAY]: { read: true, write: true }, - }; - state.relays.timestamp = 100; - LoginStore.updateSession(state); - return; - } - - if (state.relays.timestamp >= createdAt) { - return; - } - - // filter out non-websocket urls - const filtered = new Map(); - for (const [k, v] of Object.entries(relays)) { - if (k.startsWith("wss://") || k.startsWith("ws://")) { - const url = sanitizeRelayUrl(k); - if (url) { - filtered.set(url, v as RelaySettings); - } - } - } - state.relays.item = Object.fromEntries(filtered.entries()); - state.relays.timestamp = createdAt; - LoginStore.updateSession(state); -} - -export function removeRelay(state: LoginSession, addr: string) { - delete state.relays.item[addr]; - LoginStore.updateSession(state); -} - export function logout(id: string) { LoginStore.removeSession(id); GiftsCache.clear(); @@ -141,33 +107,6 @@ export function generateRandomKey() { }; } -export function setTags(state: LoginSession, tags: Array, ts: number) { - if (state.tags.timestamp >= ts) { - return; - } - state.tags.item = tags; - state.tags.timestamp = ts; - LoginStore.updateSession(state); -} - -export function setMuted(state: LoginSession, muted: Array, ts: number) { - if (state.muted.timestamp >= ts) { - return; - } - state.muted.item = muted; - state.muted.timestamp = ts; - LoginStore.updateSession(state); -} - -export function setBlocked(state: LoginSession, blocked: Array, ts: number) { - if (state.blocked.timestamp >= ts) { - return; - } - state.blocked.item = blocked; - state.blocked.timestamp = ts; - LoginStore.updateSession(state); -} - export function updateSession(id: string, fn: (state: LoginSession) => void) { const session = LoginStore.get(id); if (session) { @@ -176,37 +115,19 @@ export function updateSession(id: string, fn: (state: LoginSession) => void) { } } -export function setPinned(state: LoginSession, pinned: Array, ts: number) { - if (state.pinned.timestamp >= ts) { - return; - } - state.pinned.item = pinned; - state.pinned.timestamp = ts; - LoginStore.updateSession(state); -} - -export function setBookmarked(state: LoginSession, bookmarked: Array, ts: number) { - if (state.bookmarked.timestamp >= ts) { - return; - } - state.bookmarked.item = bookmarked; - state.bookmarked.timestamp = ts; - LoginStore.updateSession(state); -} - -export async function setAppData(state: LoginSession, data: SnortAppData, system: SystemInterface) { +export async function setAppData(state: LoginSession, data: SnortAppData) { const pub = LoginStore.getPublisher(state.id); if (!pub) return; - await state.appData.updateJson(data, pub.signer, system); + await state.state.setAppData(data); LoginStore.updateSession(state); } -export async function updateAppData(id: string, system: SystemInterface, fn: (data: SnortAppData) => SnortAppData) { +export async function updateAppData(id: string, fn: (data: SnortAppData) => SnortAppData) { const session = LoginStore.get(id); - if (session) { - const next = fn(session.appData.json); - await setAppData(session, next, system); + if (session?.state.appdata) { + const next = fn(session.state.appdata); + await setAppData(session, next); } } diff --git a/packages/app/src/Utils/Login/LoginSession.ts b/packages/app/src/Utils/Login/LoginSession.ts index e350a206..912c0503 100644 --- a/packages/app/src/Utils/Login/LoginSession.ts +++ b/packages/app/src/Utils/Login/LoginSession.ts @@ -1,4 +1,4 @@ -import { HexKey, JsonEventSync, KeyStorage, RelaySettings } from "@snort/system"; +import { HexKey, KeyStorage, UserState } from "@snort/system"; import { DisplayAs } from "@/Components/Feed/DisplayAsSelector"; import { UserPreferences } from "@/Utils/Login/index"; @@ -21,9 +21,6 @@ export const enum LoginSessionType { } export interface SnortAppData { - id: string; - mutedWords: Array; - showContentWarningPosts: boolean; preferences: UserPreferences; } @@ -64,40 +61,7 @@ export interface LoginSession { */ publicKey?: HexKey; - /** - * All the logged in users relays - */ - relays: Newest>; - - /** - * A list of pubkeys this user follows - */ - contacts: Array>; - - /** - * A list of tags this user follows - */ - tags: Newest>; - - /** - * A list of event ids this user has pinned - */ - pinned: Newest>; - - /** - * A list of event ids this user has bookmarked - */ - bookmarked: Newest>; - - /** - * A list of pubkeys this user has muted - */ - muted: Newest>; - - /** - * A list of pubkeys this user has muted privately - */ - blocked: Newest>; + state: UserState; /** * Timestamp of last read notification @@ -114,11 +78,6 @@ export interface LoginSession { */ remoteSignerRelays?: Array; - /** - * Snort application data - */ - appData: JsonEventSync; - /** * A list of chats which we have joined (NIP-28/NIP-29) */ diff --git a/packages/app/src/Utils/Login/MultiAccountStore.ts b/packages/app/src/Utils/Login/MultiAccountStore.ts index a18fa551..e70e20ac 100644 --- a/packages/app/src/Utils/Login/MultiAccountStore.ts +++ b/packages/app/src/Utils/Login/MultiAccountStore.ts @@ -3,16 +3,14 @@ import * as utils from "@noble/curves/abstract/utils"; import * as secp from "@noble/curves/secp256k1"; import { ExternalStore, unwrap } from "@snort/shared"; import { - EventKind, EventPublisher, HexKey, - JsonEventSync, KeyStorage, - NostrLink, - NostrPrefix, NotEncrypted, RelaySettings, socialGraphInstance, + UserState, + UserStateObject, } from "@snort/system"; import { v4 as uuid } from "uuid"; @@ -29,8 +27,6 @@ const LoggedOut = { item: [], timestamp: 0, }, - contacts: [], - follows: [], muted: { item: [], timestamp: 0, @@ -54,18 +50,15 @@ const LoggedOut = { latestNotification: 0, readNotifications: 0, subscriptions: [], - appData: new JsonEventSync( - { - id: "", - preferences: DefaultPreferences, - mutedWords: [], - showContentWarningPosts: false, - }, - new NostrLink(NostrPrefix.Address, "snort", EventKind.AppData), - true, - ), extraChats: [], stalker: false, + state: new UserState("", { + initAppdata: { + preferences: DefaultPreferences, + }, + encryptAppdata: true, + appdataId: "snort", + }), } as LoginSession; export class MultiAccountStore extends ExternalStore { @@ -75,7 +68,7 @@ export class MultiAccountStore extends ExternalStore { constructor() { super(); - if (typeof ServiceWorkerGlobalScope !== "undefined" && self instanceof ServiceWorkerGlobalScope) { + if (typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope) { // return if sw. we might want to use localForage (idb) to share keys between sw and app return; } @@ -103,14 +96,23 @@ export class MultiAccountStore extends ExternalStore { if (v.privateKeyData) { v.privateKeyData = KeyStorage.fromPayload(v.privateKeyData as object); } - v.appData = new JsonEventSync( - v.appData as unknown as SnortAppData, - new NostrLink(NostrPrefix.Address, "snort", EventKind.AppData, v.publicKey), - true, + const stateObj = v.state as unknown as UserStateObject | undefined; + const stateClass = new UserState( + v.publicKey!, + { + initAppdata: stateObj?.appdata ?? { + preferences: { + ...DefaultPreferences, + ...CONFIG.defaultPreferences, + }, + }, + encryptAppdata: true, + appdataId: "snort", + }, + stateObj, ); - v.appData.on("change", () => { - this.#save(); - }); + stateClass.on("change", () => this.#save()); + v.state = stateClass; } this.#loadIrisKeyIfExists(); } @@ -174,24 +176,22 @@ export class MultiAccountStore extends ExternalStore { item: initRelays, timestamp: 1, }, - appData: new JsonEventSync( - { - id: "", + state: new UserState(key, { + initAppdata: { preferences: { ...DefaultPreferences, ...CONFIG.defaultPreferences, }, - mutedWords: [], - showContentWarningPosts: false, }, - new NostrLink(NostrPrefix.Address, "snort", EventKind.AppData, key), - true, - ), + encryptAppdata: true, + appdataId: "snort", + }), remoteSignerRelays, privateKeyData: privateKey, stalker: stalker ?? false, } as LoginSession; + newSession.state.on("change", () => this.#save()); const pub = createPublisher(newSession); if (pub) { this.setPublisher(newSession.id, pub); @@ -229,20 +229,18 @@ export class MultiAccountStore extends ExternalStore { item: initRelays, timestamp: 1, }, - appData: new JsonEventSync( - { - id: "", + state: new UserState(pubKey, { + initAppdata: { preferences: { ...DefaultPreferences, ...CONFIG.defaultPreferences, }, - mutedWords: [], - showContentWarningPosts: false, }, - new NostrLink(NostrPrefix.Address, "snort", EventKind.AppData, pubKey), - true, - ), + encryptAppdata: true, + appdataId: "snort", + }), } as LoginSession; + newSession.state.on("change", () => this.#save()); if ("nostr_os" in window && window?.nostr_os) { window?.nostr_os.saveKey(key.value); @@ -300,14 +298,43 @@ export class MultiAccountStore extends ExternalStore { #migrate() { let didMigrate = false; + // delete some old keys for (const [, acc] of this.#accounts) { - if ("item" in acc.appData) { + if ("appData" in acc) { + delete acc["appData"]; + didMigrate = true; + } + if ("contacts" in acc) { + delete acc["contacts"]; + didMigrate = true; + } + if ("follows" in acc) { + delete acc["follows"]; + didMigrate = true; + } + if ("relays" in acc) { + delete acc["relays"]; + didMigrate = true; + } + if ("blocked" in acc) { + delete acc["blocked"]; + didMigrate = true; + } + if ("bookmarked" in acc) { + delete acc["bookmarked"]; + didMigrate = true; + } + if ("muted" in acc) { + delete acc["muted"]; + didMigrate = true; + } + if ("pinned" in acc) { + delete acc["pinned"]; + didMigrate = true; + } + if ("tags" in acc) { + delete acc["tags"]; didMigrate = true; - acc.appData = new JsonEventSync( - acc.appData.item as SnortAppData, - new NostrLink(NostrPrefix.Address, "snort", EventKind.AppData, acc.publicKey), - true, - ); } } @@ -326,17 +353,18 @@ export class MultiAccountStore extends ExternalStore { if (v.privateKeyData instanceof KeyStorage) { toSave.push({ ...v, - appData: v.appData.json, + state: v.state instanceof UserState ? v.state.serialize() : v.state, privateKeyData: v.privateKeyData.toPayload(), }); } else { toSave.push({ ...v, - appData: v.appData.json, + state: v.state instanceof UserState ? v.state.serialize() : v.state, }); } } + console.debug("Trying to save", toSave); window.localStorage.setItem(AccountStoreKey, JSON.stringify(toSave)); this.notifyChange(); } diff --git a/packages/app/src/Utils/Login/Preferences.ts b/packages/app/src/Utils/Login/Preferences.ts index e05e0cce..cd1d1160 100644 --- a/packages/app/src/Utils/Login/Preferences.ts +++ b/packages/app/src/Utils/Login/Preferences.ts @@ -102,6 +102,11 @@ export interface UserPreferences { * Hides muted notes when selected */ hideMutedNotes: boolean; + + /** + * Show posts with content warning + */ + showContentWarningPosts: boolean; } export const DefaultPreferences = { @@ -123,4 +128,5 @@ export const DefaultPreferences = { checkSigs: true, autoTranslate: true, hideMutedNotes: false, + showContentWarningPosts: false, } as UserPreferences; diff --git a/packages/app/src/Utils/Thread/ChainKey.tsx b/packages/app/src/Utils/Thread/ChainKey.tsx index 8cf320a1..31d2998d 100644 --- a/packages/app/src/Utils/Thread/ChainKey.tsx +++ b/packages/app/src/Utils/Thread/ChainKey.tsx @@ -1,18 +1,22 @@ -import { unwrap } from "@snort/shared"; -import { EventExt, NostrLink, TaggedNostrEvent } from "@snort/system"; +import { Nip10, NostrLink, TaggedNostrEvent } from "@snort/system"; /** * Get the chain key as a reply event + * + * ie. Get the key for which this event is replying to */ export function replyChainKey(ev: TaggedNostrEvent) { - const t = EventExt.extractThread(ev); - return t?.replyTo?.value ?? t?.root?.value; + const t = Nip10.parseThread(ev); + const tag = t?.replyTo ?? t?.root; + return tag?.tagKey; } /** * Get the chain key of this event + * + * ie. Get the key which ties replies to this event */ export function chainKey(ev: TaggedNostrEvent) { const link = NostrLink.fromEvent(ev); - return unwrap(link.toEventTag())[1]; + return link.tagKey; } diff --git a/packages/app/src/Utils/Thread/ThreadContextWrapper.tsx b/packages/app/src/Utils/Thread/ThreadContextWrapper.tsx index f43fd338..aa436ad3 100644 --- a/packages/app/src/Utils/Thread/ThreadContextWrapper.tsx +++ b/packages/app/src/Utils/Thread/ThreadContextWrapper.tsx @@ -12,13 +12,13 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil const location = useLocation(); const [currentId, setCurrentId] = useState(unwrap(link.toEventTag())[1]); const feed = useThreadFeed(link); - const { isBlocked } = useModeration(); + const { isMuted } = useModeration(); const chains = useMemo(() => { const chains = new Map>(); if (feed) { feed - ?.filter(a => !isBlocked(a.pubkey)) + ?.filter(a => !isMuted(a.pubkey)) .forEach(v => { const replyTo = replyChainKey(v); if (replyTo) { @@ -31,7 +31,7 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil }); } return chains; - }, [feed]); + }, [feed, isMuted]); // Root is the parent of the current note or the current note if its a root note or the root of the thread const root = useMemo(() => { @@ -46,7 +46,7 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil return currentNote; } } - }, [feed.length, currentId, location]); + }, [feed, location.state, currentId]); const ctxValue = useMemo(() => { return { @@ -56,7 +56,7 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil data: feed, setCurrent: v => setCurrentId(v), }; - }, [root, chains]); + }, [currentId, root, chains, feed]); return {children}; } diff --git a/packages/app/src/Utils/Upload/index.ts b/packages/app/src/Utils/Upload/index.ts index a9f88633..e9519f3c 100644 --- a/packages/app/src/Utils/Upload/index.ts +++ b/packages/app/src/Utils/Upload/index.ts @@ -3,7 +3,7 @@ import { useState } from "react"; import { v4 as uuid } from "uuid"; import useEventPublisher from "@/Hooks/useEventPublisher"; -import useLogin from "@/Hooks/useLogin"; +import usePreferences from "@/Hooks/usePreferences"; import { bech32ToHex, unwrap } from "@/Utils"; import { KieranPubKey } from "@/Utils/Const"; import NostrBuild from "@/Utils/Upload/NostrBuild"; @@ -65,7 +65,7 @@ export interface UploadProgress { export type UploadStage = "starting" | "hashing" | "uploading" | "done" | undefined; export default function useFileUpload(): Uploader { - const fileUploader = useLogin(s => s.appData.json.preferences.fileUploader); + const fileUploader = usePreferences(s => s.fileUploader); const { publisher } = useEventPublisher(); const [progress, setProgress] = useState>([]); const [stage, setStage] = useState(); diff --git a/packages/app/src/Utils/index.ts b/packages/app/src/Utils/index.ts index e6dc3234..ec7f5819 100644 --- a/packages/app/src/Utils/index.ts +++ b/packages/app/src/Utils/index.ts @@ -437,9 +437,10 @@ export function getUrlHostname(url?: string) { } } -export function sanitizeRelayUrl(url: string) { +export function sanitizeRelayUrl(url?: string) { + if ((url?.length ?? 0) === 0) return; try { - return new URL(url).toString(); + return new URL(url!).toString(); } catch { // ignore } @@ -537,7 +538,7 @@ export function trackEvent( if ( !import.meta.env.DEV && CONFIG.features.analytics && - (LoginStore.snapshot().appData.json.preferences.telemetry ?? true) + (LoginStore.snapshot().state.appdata?.preferences.telemetry ?? true) ) { fetch("https://pa.v0l.io/api/event", { method: "POST", @@ -547,9 +548,9 @@ export function trackEvent( body: JSON.stringify({ d: CONFIG.hostname, n: event, - r: document.referrer === location.href ? null : document.referrer, + r: document.referrer === window.location.href ? null : document.referrer, p: props, - u: e?.destination?.url ?? `${location.protocol}//${location.host}${location.pathname}`, + u: e?.destination?.url ?? `${window.location.protocol}//${window.location.host}${window.location.pathname}`, }), }); } diff --git a/packages/app/src/chat/index.ts b/packages/app/src/chat/index.ts index 1a9e3af8..dca2f951 100644 --- a/packages/app/src/chat/index.ts +++ b/packages/app/src/chat/index.ts @@ -169,19 +169,19 @@ export function useChatSystem(chat: ChatSystem) { const login = useLogin(); const sub = useMemo(() => { return chat.subscription(login); - }, [login.publicKey]); + }, [chat, login]); const data = useRequestBuilder(sub); - const { isBlocked } = useModeration(); + const { isMuted } = useModeration(); return useMemo(() => { if (login.publicKey) { return chat.listChats( login.publicKey, - data.filter(a => !isBlocked(a.pubkey)), + data.filter(a => !isMuted(a.pubkey)), ); } return []; - }, [login.publicKey, data]); + }, [chat, login, data, isMuted]); } export function useChatSystems() { diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 2abad410..71d3f2a8 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -12,7 +12,6 @@ import { ThreadRoute } from "@/Components/Event/Thread/ThreadRoute"; import { IntlProvider } from "@/Components/IntlProvider/IntlProvider"; import { db } from "@/Db"; import { addCachedMetadataToFuzzySearch } from "@/Db/FuzzySearch"; -import { updateRelayConnections } from "@/Hooks/useLoginRelays"; import { AboutPage } from "@/Pages/About"; import { SnortDeckLayout } from "@/Pages/Deck/DeckLayout"; import DonatePage from "@/Pages/Donate/DonatePage"; @@ -39,10 +38,10 @@ import { WalletSendPage } from "@/Pages/wallet/send"; import ZapPoolPage from "@/Pages/ZapPool/ZapPool"; import { System } from "@/system"; import { storeRefCode, unwrap } from "@/Utils"; -import { LoginStore } from "@/Utils/Login"; import { hasWasm, wasmInit, WasmPath } from "@/Utils/wasm"; import { Wallets } from "@/Wallet"; import { setupWebLNWalletConfig } from "@/Wallet"; +import { LoginStore } from "./Utils/Login"; async function initSite() { storeRefCode(); @@ -50,15 +49,14 @@ async function initSite() { await wasmInit(WasmPath); await initRelayWorker(); } - const login = LoginStore.takeSnapshot(); - updateRelayConnections(System, login.relays.item).catch(console.error); + setupWebLNWalletConfig(Wallets); db.ready = await db.isAvailable(); if (db.ready) { - const pTags = login.contacts.filter(a => a[0] === "p").map(a => a[1]); - await preload(pTags); - await System.PreloadSocialGraph(); + const login = LoginStore.snapshot(); + preload(login.state.follows); // dont await this + System.PreloadSocialGraph(); // dont await this } queueMicrotask(() => { diff --git a/packages/app/src/service-worker.ts b/packages/app/src/service-worker.ts index 6496ce28..36f90bbe 100644 --- a/packages/app/src/service-worker.ts +++ b/packages/app/src/service-worker.ts @@ -1,10 +1,6 @@ /// import { CacheableResponsePlugin } from "workbox-cacheable-response"; -declare const self: ServiceWorkerGlobalScope & { - __WB_MANIFEST: (string | PrecacheEntry)[]; -}; - import { encodeTLVEntries, NostrLink, NostrPrefix, TLVEntryType, tryParseNostrLink } from "@snort/system"; import { clientsClaim } from "workbox-core"; import { ExpirationPlugin } from "workbox-expiration"; @@ -15,12 +11,16 @@ import { CacheFirst, StaleWhileRevalidate } from "workbox-strategies"; import { defaultAvatar, hexToBech32 } from "@/Utils"; import { formatShort } from "@/Utils/Number"; +declare const self: ServiceWorkerGlobalScope & { + __WB_MANIFEST: (string | PrecacheEntry)[]; +}; + precacheAndRoute(self.__WB_MANIFEST); clientsClaim(); // cache everything in current domain /assets because precache doesn't seem to include everything registerRoute( - ({ url }) => url.origin === location.origin && url.pathname.startsWith("/assets"), + ({ url }) => url.origin === window.location.origin && url.pathname.startsWith("/assets"), new StaleWhileRevalidate({ cacheName: "assets-cache", plugins: [ diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index 8d47b428..9b7dd84d 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -201,7 +201,7 @@ export async function fetchNostrAddress(name: string, domain: string, timeout = } export function removeUndefined(v: Array) { - return v.filter(a => a != undefined).map(a => unwrap(a)); + return v.filter(a => a !== undefined).map(a => unwrap(a)); } /** diff --git a/packages/system/src/connection-pool.ts b/packages/system/src/connection-pool.ts index d23e7dc7..cb08cb97 100644 --- a/packages/system/src/connection-pool.ts +++ b/packages/system/src/connection-pool.ts @@ -5,7 +5,6 @@ import { EventEmitter } from "eventemitter3"; import { Connection, RelaySettings } from "./connection"; import { NostrEvent, OkResponse, TaggedNostrEvent } from "./nostr"; import { SystemInterface } from "."; -import LRUSet from "@snort/shared/src/LRUSet"; export interface NostrConnectionPoolEvents { connected: (address: string, wasReconnect: boolean) => void; @@ -38,7 +37,6 @@ export class DefaultConnectionPool extends EventEmitter(); - #requestedIds = new LRUSet(1000); constructor(system: SystemInterface) { super(); @@ -49,7 +47,8 @@ export class DefaultConnectionPool extends EventEmitter { #activity: number = unixNowMs(); #expectAuth = false; #ephemeral: boolean; + #closing = false; + #downCount = 0; + #activeRequests = new Set(); Id: string; readonly Address: string; @@ -58,26 +61,22 @@ export class Connection extends EventEmitter { PendingRaw: Array = []; PendingRequests: Array = []; - ActiveRequests = new Set(); Settings: RelaySettings; Info?: RelayInfo; ConnectTimeout: number = DefaultConnectTimeout; HasStateChange: boolean = true; - IsClosed: boolean; ReconnectTimer?: ReturnType; EventsCallback: Map) => void>; AwaitingAuth: Map; Authed = false; - Down = true; constructor(addr: string, options: RelaySettings, ephemeral: boolean = false) { super(); this.Id = uuid(); this.Address = addr; this.Settings = options; - this.IsClosed = false; this.EventsCallback = new Map(); this.AwaitingAuth = new Map(); this.#ephemeral = ephemeral; @@ -93,7 +92,20 @@ export class Connection extends EventEmitter { this.#setupEphemeral(); } + get isOpen() { + return this.Socket?.readyState === WebSocket.OPEN; + } + + get isDown() { + return this.#downCount > 0; + } + + get ActiveRequests() { + return [...this.#activeRequests]; + } + async connect() { + if (this.isOpen) return; try { if (this.Info === undefined) { const u = new URL(this.Address); @@ -116,7 +128,7 @@ export class Connection extends EventEmitter { // ignored } - const wasReconnect = this.Socket !== null && !this.IsClosed; + const wasReconnect = this.Socket !== null; if (this.Socket) { this.Id = uuid(); this.Socket.onopen = null; @@ -125,7 +137,6 @@ export class Connection extends EventEmitter { this.Socket.onclose = null; this.Socket = null; } - this.IsClosed = false; this.Socket = new WebSocket(this.Address); this.Socket.onopen = () => this.#onOpen(wasReconnect); this.Socket.onmessage = e => this.#onMessage(e); @@ -133,52 +144,57 @@ export class Connection extends EventEmitter { this.Socket.onclose = e => this.#onClose(e); } - close() { - this.IsClosed = true; + close(final = true) { + if (final) { + this.#closing = true; + } this.Socket?.close(); } #onOpen(wasReconnect: boolean) { - this.ConnectTimeout = DefaultConnectTimeout; + this.#downCount = 0; this.#log(`Open!`); - this.Down = false; this.#setupEphemeral(); this.emit("connected", wasReconnect); this.#sendPendingRaw(); } #onClose(e: WebSocket.CloseEvent) { - if (this.ReconnectTimer) { - clearTimeout(this.ReconnectTimer); - this.ReconnectTimer = undefined; - } - // remote server closed the connection, dont re-connect - if (e.code === 4000) { - this.IsClosed = true; - this.#log(`Closed! (Remote)`); - } else if (!this.IsClosed) { - this.ConnectTimeout = this.ConnectTimeout * this.ConnectTimeout; - this.#log( - `Closed (code=${e.code}), trying again in ${(this.ConnectTimeout / 1000).toFixed(0).toLocaleString()} sec`, - ); - this.ReconnectTimer = setTimeout(() => { - try { - this.connect(); - } catch { - this.emit("disconnect", -1); - } - }, this.ConnectTimeout); - // todo: stats disconnect + if (!this.#closing) { + this.#downCount++; + this.#reconnectTimer(e); } else { this.#log(`Closed!`); - this.ReconnectTimer = undefined; + this.#downCount = 0; + if (this.ReconnectTimer) { + clearTimeout(this.ReconnectTimer); + this.ReconnectTimer = undefined; + } } this.emit("disconnect", e.code); this.#reset(); } + #reconnectTimer(e: WebSocket.CloseEvent) { + if (this.ReconnectTimer) { + clearTimeout(this.ReconnectTimer); + this.ReconnectTimer = undefined; + } + this.ConnectTimeout = this.ConnectTimeout * 2; + this.#log( + `Closed (code=${e.code}), trying again in ${(this.ConnectTimeout / 1000).toFixed(0).toLocaleString()} sec`, + ); + this.ReconnectTimer = setTimeout(() => { + try { + this.connect(); + } catch { + this.emit("disconnect", -1); + } + }, this.ConnectTimeout); + } + #onMessage(e: WebSocket.MessageEvent) { this.#activity = unixNowMs(); if ((e.data as string).length > 0) { @@ -332,14 +348,13 @@ export class Connection extends EventEmitter { this.#expectAuth = true; this.#log("Setting expectAuth flag %o", requestKinds); } - if (this.ActiveRequests.size >= this.#maxSubscriptions) { + if (this.#activeRequests.size >= this.#maxSubscriptions) { this.PendingRequests.push({ obj: cmd, cb: cbSent, }); this.#log("Queuing: %O", cmd); } else { - this.ActiveRequests.add(cmd[1]); this.#sendRequestCommand({ obj: cmd, cb: cbSent, @@ -350,7 +365,7 @@ export class Connection extends EventEmitter { } closeReq(id: string) { - if (this.ActiveRequests.delete(id)) { + if (this.#activeRequests.delete(id)) { this.send(["CLOSE", id]); this.emit("eose", id); this.#sendQueuedRequests(); @@ -359,7 +374,7 @@ export class Connection extends EventEmitter { } #sendQueuedRequests() { - const canSend = this.#maxSubscriptions - this.ActiveRequests.size; + const canSend = this.#maxSubscriptions - this.#activeRequests.size; if (canSend > 0) { for (let x = 0; x < canSend; x++) { const p = this.PendingRequests.shift(); @@ -375,12 +390,12 @@ export class Connection extends EventEmitter { try { const cmd = item.obj; if (cmd[0] === "REQ" || cmd[0] === "GET") { - this.ActiveRequests.add(cmd[1]); + this.#activeRequests.add(cmd[1]); this.send(cmd); } else if (cmd[0] === "SYNC") { const [_, id, eventSet, ...filters] = cmd; const lastResortSync = () => { - if (filters.some(a => a.since || a.until)) { + if (filters.some(a => a.since || a.until || a.ids)) { this.queueReq(["REQ", id, ...filters], item.cb); } else { const latest = eventSet.reduce((acc, v) => (acc = v.created_at > acc ? v.created_at : acc), 0); @@ -391,7 +406,7 @@ export class Connection extends EventEmitter { this.queueReq(["REQ", id, ...newFilters], item.cb); } }; - if (this.Address.startsWith("wss://relay.snort.social")) { + if (this.Info?.negentropy === "v1") { const newFilters = filters; const neg = new NegentropyFlow(id, this, eventSet, newFilters); neg.once("finish", filters => { @@ -419,19 +434,34 @@ export class Connection extends EventEmitter { // reset connection Id on disconnect, for query-tracking this.Id = uuid(); this.#expectAuth = false; - this.ActiveRequests.clear(); + this.#log( + "Reset active=%O, pending=%O, raw=%O", + [...this.#activeRequests], + [...this.PendingRequests], + [...this.PendingRaw], + ); + for (const active of this.#activeRequests) { + this.emit("closed", active, "connection closed"); + } + for (const pending of this.PendingRequests) { + this.emit("closed", pending.obj[1], "connection closed"); + } + for (const raw of this.PendingRaw) { + if (Array.isArray(raw) && raw[0] === "REQ") { + this.emit("closed", raw[1], "connection closed"); + } + } + this.#activeRequests.clear(); this.PendingRequests = []; this.PendingRaw = []; + this.emit("change"); } send(obj: object) { const authPending = !this.Authed && (this.AwaitingAuth.size > 0 || this.Info?.limitation?.auth_required === true); - if (!this.Socket || this.Socket?.readyState !== WebSocket.OPEN || authPending) { + if (!this.isOpen || authPending) { this.PendingRaw.push(obj); - if (this.Socket?.readyState === WebSocket.CLOSED && this.Ephemeral && this.IsClosed) { - this.connect(); - } return false; } @@ -503,11 +533,15 @@ export class Connection extends EventEmitter { if (this.Ephemeral) { this.#ephemeralCheck = setInterval(() => { const lastActivity = unixNowMs() - this.#activity; - if (lastActivity > 30_000 && !this.IsClosed) { - if (this.ActiveRequests.size > 0) { - this.#log("Inactive connection has %d active requests! %O", this.ActiveRequests.size, this.ActiveRequests); + if (lastActivity > 30_000 && !this.#closing) { + if (this.#activeRequests.size > 0) { + this.#log( + "Inactive connection has %d active requests! %O", + this.#activeRequests.size, + this.#activeRequests, + ); } else { - this.close(); + this.close(false); } } }, 5_000); diff --git a/packages/system/src/event-builder.ts b/packages/system/src/event-builder.ts index 3faac790..5b864131 100644 --- a/packages/system/src/event-builder.ts +++ b/packages/system/src/event-builder.ts @@ -1,4 +1,4 @@ -import { EventKind, HexKey, NostrPrefix, NostrEvent, EventSigner, PowMiner } from "."; +import { EventKind, HexKey, NostrPrefix, NostrEvent, EventSigner, PowMiner, NotSignedNostrEvent } from "."; import { HashtagRegex, MentionNostrEntityRegex } from "./const"; import { getPublicKey, jitter, unixNow } from "@snort/shared"; import { EventExt } from "./event-ext"; @@ -14,6 +14,10 @@ export class EventBuilder { #powMiner?: PowMiner; #jitter?: number; + get pubkey() { + return this.#pubkey; + } + /** * Populate builder with values from link */ diff --git a/packages/system/src/event-ext.ts b/packages/system/src/event-ext.ts index 3434f884..5e1d549a 100644 --- a/packages/system/src/event-ext.ts +++ b/packages/system/src/event-ext.ts @@ -11,6 +11,7 @@ export interface Tag { value?: string; relay?: string; marker?: string; // NIP-10 + author?: string; // NIP-10 "pubkey-stub" } export interface Thread { @@ -48,9 +49,6 @@ export abstract class EventExt { const sig = secp.schnorr.sign(e.id, key); e.sig = utils.bytesToHex(sig); - if (!secp.schnorr.verify(e.sig, e.id, e.pubkey)) { - throw new Error("Signing failed"); - } return e; } @@ -102,10 +100,15 @@ export abstract class EventExt { value: tag[1], } as Tag; switch (ret.key) { - case "a": + case "a": { + ret.relay = tag[2]; + ret.marker = tag[3]; + break; + } case "e": { - ret.relay = tag.length > 2 ? tag[2] : undefined; - ret.marker = tag.length > 3 ? tag[3] : undefined; + ret.relay = tag[2]; + ret.marker = tag[3]; + ret.author = tag[4]; break; } } diff --git a/packages/system/src/event-publisher.ts b/packages/system/src/event-publisher.ts index 6a6cb7ae..0ff6bb66 100644 --- a/packages/system/src/event-publisher.ts +++ b/packages/system/src/event-publisher.ts @@ -15,6 +15,7 @@ import { PowMiner, PrivateKeySigner, RelaySettings, + settingsToRelayTag, SignerSupports, TaggedNostrEvent, ToNostrEventTag, @@ -23,10 +24,10 @@ import { } from "."; import { EventBuilder } from "./event-builder"; -import { EventExt } from "./event-ext"; import { findTag } from "./utils"; import { Nip7Signer } from "./impl/nip7"; import { base64 } from "@scure/base"; +import { Nip10 } from "./impl/nip10"; type EventBuilderHook = (ev: EventBuilder) => EventBuilder; @@ -202,29 +203,7 @@ export class EventPublisher { const eb = this.#eb(EventKind.TextNote); eb.content(msg); - const link = NostrLink.fromEvent(replyTo); - const thread = EventExt.extractThread(replyTo); - if (thread) { - const rootOrReplyAsRoot = thread.root || thread.replyTo; - if (rootOrReplyAsRoot) { - eb.tag([rootOrReplyAsRoot.key, rootOrReplyAsRoot.value ?? "", rootOrReplyAsRoot.relay ?? "", "root"]); - } - eb.tag([...unwrap(link.toEventTag()), "reply"]); - - eb.tag(["p", replyTo.pubkey]); - for (const pk of thread.pubKeys) { - if (pk === this.#pubKey) { - continue; - } - eb.tag(["p", pk]); - } - } else { - eb.tag([...unwrap(link.toEventTag()), "root"]); - // dont tag self in replies - if (replyTo.pubkey !== this.#pubKey) { - eb.tag(["p", replyTo.pubkey]); - } - } + Nip10.replyTo(replyTo, eb); eb.processContent(); fnExtra?.(eb); return await this.#sign(eb); @@ -247,15 +226,9 @@ export class EventPublisher { } const eb = this.#eb(EventKind.Relays); for (const rx of relays) { - const rTag = ["r", rx.url]; - if (rx.settings.read && !rx.settings.write) { - rTag.push("read"); - } - if (rx.settings.write && !rx.settings.read) { - rTag.push("write"); - } - if (rx.settings.read || rx.settings.write) { - eb.tag(rTag); + const tag = settingsToRelayTag(rx); + if (tag) { + eb.tag(tag); } } return await this.#sign(eb); diff --git a/packages/system/src/impl/nip10.ts b/packages/system/src/impl/nip10.ts new file mode 100644 index 00000000..e0850c4c --- /dev/null +++ b/packages/system/src/impl/nip10.ts @@ -0,0 +1,73 @@ +import { dedupe, unwrap } from "@snort/shared"; +import { EventBuilder } from "../event-builder"; +import { NostrEvent } from "../nostr"; +import { NostrLink } from "../nostr-link"; + +export interface Nip10Thread { + root?: NostrLink; + replyTo?: NostrLink; + mentions: Array; + pubKeys: Array; +} + +/** + * Utility class which exports functions used in NIP-10 + */ +export class Nip10 { + /** + * Reply to an event using NIP-10 tagging + */ + static replyTo(ev: NostrEvent, eb: EventBuilder) { + const link = NostrLink.fromEvent(ev); + const thread = Nip10.parseThread(ev); + if (thread) { + const rootOrReplyAsRoot = thread.root || thread.replyTo; + if (rootOrReplyAsRoot) { + eb.tag(unwrap(rootOrReplyAsRoot.toEventTag("root"))); + } + eb.tag(unwrap(link.toEventTag("reply"))); + + for (const pk of thread.pubKeys) { + if (pk.id === eb.pubkey) { + continue; + } + eb.tag(unwrap(pk.toEventTag())); + } + } else { + eb.tag(unwrap(link.toEventTag("root"))); + if (ev.pubkey !== eb.pubkey) { + eb.tag(["p", ev.pubkey]); + } + } + } + + static parseThread(ev: NostrEvent) { + const ret = { + mentions: [], + pubKeys: [], + } as Nip10Thread; + const replyTags = ev.tags.filter(a => a[0] === "e" || a[0] === "a").map(a => NostrLink.fromTag(a)); + if (replyTags.length > 0) { + const marked = replyTags.some(a => a.marker); + if (!marked) { + ret.root = replyTags[0]; + if (replyTags.length > 1) { + ret.replyTo = replyTags[replyTags.length - 1]; + } + if (replyTags.length > 2) { + ret.mentions = replyTags.slice(1, -1); + } + } else { + const root = replyTags.find(a => a.marker === "root"); + const reply = replyTags.find(a => a.marker === "reply"); + ret.root = root; + ret.replyTo = reply; + ret.mentions = replyTags.filter(a => a.marker === "mention"); + } + } else { + return undefined; + } + ret.pubKeys = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1])).map(a => NostrLink.publicKey(a)); + return ret; + } +} diff --git a/packages/system/src/zaps.ts b/packages/system/src/impl/nip57.ts similarity index 90% rename from packages/system/src/zaps.ts rename to packages/system/src/impl/nip57.ts index fcb7d482..f5627095 100644 --- a/packages/system/src/zaps.ts +++ b/packages/system/src/impl/nip57.ts @@ -1,10 +1,10 @@ -import { decodeInvoice, InvoiceDetails } from "@snort/shared"; -import { NostrEvent } from "./nostr"; -import { findTag } from "./utils"; -import { EventExt } from "./event-ext"; -import { NostrLink } from "./nostr-link"; import debug from "debug"; import { LRUCache } from "lru-cache"; +import { decodeInvoice, InvoiceDetails } from "@snort/shared"; +import { NostrEvent } from "../nostr"; +import { findTag } from "../utils"; +import { NostrLink } from "../nostr-link"; +import { Nip10 } from "./nip10"; const Log = debug("zaps"); const ParsedZapCache = new LRUCache({ max: 1000 }); @@ -35,7 +35,7 @@ export function parseZap(zapReceipt: NostrEvent): ParsedZap { // old format, ignored throw new Error("deprecated zap format"); } - const zapRequestThread = EventExt.extractThread(zapRequest); + const zapRequestThread = Nip10.parseThread(zapRequest); const requestContext = zapRequestThread?.root; const anonZap = zapRequest.tags.find(a => a[0] === "anon"); @@ -44,7 +44,7 @@ export function parseZap(zapReceipt: NostrEvent): ParsedZap { id: zapReceipt.id, zapService: zapReceipt.pubkey, amount: (invoice?.amount ?? 0) / 1000, - event: requestContext ? NostrLink.fromThreadTag(requestContext) : undefined, + event: requestContext, sender: zapRequest.pubkey, receiver: findTag(zapRequest, "p"), valid: true, diff --git a/packages/system/src/index.ts b/packages/system/src/index.ts index c9200991..ada1655a 100644 --- a/packages/system/src/index.ts +++ b/packages/system/src/index.ts @@ -30,7 +30,7 @@ export * from "./event-publisher"; export * from "./event-builder"; export * from "./nostr-link"; export * from "./profile-cache"; -export * from "./zaps"; +export * from "./impl/nip57"; export * from "./signer"; export * from "./text"; export * from "./pow"; @@ -39,11 +39,14 @@ export * from "./query-optimizer"; export * from "./encrypted"; export * from "./outbox"; export * from "./sync"; +export * from "./user-state"; export * from "./impl/nip4"; -export * from "./impl/nip44"; export * from "./impl/nip7"; +export * from "./impl/nip10"; +export * from "./impl/nip44"; export * from "./impl/nip46"; +export * from "./impl/nip57"; export * from "./cache/index"; export * from "./cache/user-relays"; diff --git a/packages/system/src/nostr-link.ts b/packages/system/src/nostr-link.ts index 1e37236b..560d6a1c 100644 --- a/packages/system/src/nostr-link.ts +++ b/packages/system/src/nostr-link.ts @@ -19,7 +19,7 @@ export interface ToNostrEventTag { export class NostrHashtagLink implements ToNostrEventTag { constructor(readonly tag: string) {} - toEventTag(): string[] | undefined { + toEventTag() { return ["t", this.tag]; } } @@ -31,6 +31,7 @@ export class NostrLink implements ToNostrEventTag { readonly kind?: number, readonly author?: string, readonly relays?: Array, + readonly marker?: string, ) { if (type !== NostrPrefix.Address && !isHex(id)) { throw new Error("ID must be hex"); @@ -52,22 +53,43 @@ export class NostrLink implements ToNostrEventTag { } } - toEventTag(marker?: string) { - const relayEntry = this.relays?.at(0) ? [this.relays[0]] : []; + get tagKey() { + if (this.type === NostrPrefix.Address) { + return `${this.kind}:${this.author}:${this.id}`; + } + return this.id; + } + /** + * Create an event tag for this link + */ + toEventTag(marker?: string) { + const suffix: Array = []; + if (this.relays && this.relays.length > 0) { + suffix.push(this.relays[0]); + } if (marker) { - if (relayEntry.length === 0) { - relayEntry.push(""); + if (suffix[0] === undefined) { + suffix.push(""); // empty relay hint } - relayEntry.push(marker); + suffix.push(marker); } if (this.type === NostrPrefix.PublicKey || this.type === NostrPrefix.Profile) { - return ["p", this.id, ...relayEntry]; + return ["p", this.id, ...suffix]; } else if (this.type === NostrPrefix.Note || this.type === NostrPrefix.Event) { - return ["e", this.id, ...relayEntry]; + if (this.author) { + if (suffix[0] === undefined) { + suffix.push(""); // empty relay hint + } + if (suffix[1] === undefined) { + suffix.push(""); // empty marker + } + suffix.push(this.author); + } + return ["e", this.id, ...suffix]; } else if (this.type === NostrPrefix.Address) { - return ["a", `${this.kind}:${this.author}:${this.id}`, ...relayEntry]; + return ["a", `${this.kind}:${this.author}:${this.id}`, ...suffix]; } } @@ -162,46 +184,38 @@ export class NostrLink implements ToNostrEventTag { } } - static fromThreadTag(tag: Tag) { - const relay = tag.relay ? [tag.relay] : undefined; - - switch (tag.key) { - case "e": { - return new NostrLink(NostrPrefix.Event, unwrap(tag.value), undefined, undefined, relay); - } - case "p": { - return new NostrLink(NostrPrefix.Profile, unwrap(tag.value), undefined, undefined, relay); - } - case "a": { - const [kind, author, dTag] = unwrap(tag.value).split(":"); - return new NostrLink(NostrPrefix.Address, dTag, Number(kind), author, relay); - } - } - throw new Error(`Unknown tag kind ${tag.key}`); - } - - static fromTag(tag: Array, author?: string, kind?: number) { + static fromTag( + tag: Array, + author?: string, + kind?: number, + fnOther?: (tag: Array) => T, + ) { const relays = tag.length > 2 ? [tag[2]] : undefined; switch (tag[0]) { case "e": { - return new NostrLink(NostrPrefix.Event, tag[1], kind, author, relays); + return new NostrLink(NostrPrefix.Event, tag[1], kind, author ?? tag[4], relays, tag[3]); } case "p": { return new NostrLink(NostrPrefix.Profile, tag[1], kind, author, relays); } case "a": { const [kind, author, dTag] = tag[1].split(":"); - return new NostrLink(NostrPrefix.Address, dTag, Number(kind), author, relays); + return new NostrLink(NostrPrefix.Address, dTag, Number(kind), author, relays, tag[3]); + } + default: { + if (fnOther) { + return fnOther(tag); + } } } throw new Error(`Unknown tag kind ${tag[0]}`); } - static fromTags(tags: Array>) { + static fromTags(tags: ReadonlyArray>, fnOther?: (tag: Array) => T) { return removeUndefined( tags.map(a => { try { - return NostrLink.fromTag(a); + return NostrLink.fromTag(a, undefined, undefined, fnOther); } catch { // ignored, cant be mapped } @@ -218,6 +232,14 @@ export class NostrLink implements ToNostrEventTag { } return new NostrLink(NostrPrefix.Event, ev.id, ev.kind, ev.pubkey, relays); } + + static profile(pk: string, relays?: Array) { + return new NostrLink(NostrPrefix.Profile, pk, undefined, undefined, relays); + } + + static publicKey(pk: string, relays?: Array) { + return new NostrLink(NostrPrefix.PublicKey, pk, undefined, undefined, relays); + } } export function validateNostrLink(link: string): boolean { diff --git a/packages/system/src/note-collection.ts b/packages/system/src/note-collection.ts index 625164d1..1b6c18b1 100644 --- a/packages/system/src/note-collection.ts +++ b/packages/system/src/note-collection.ts @@ -70,8 +70,7 @@ export class KeyedReplaceableNoteStore extends HookedNoteStore { ev.forEach(a => { const keyOnEvent = this.#keyFn(a); const existing = this.#events.get(keyOnEvent); - const existingCreated = existing?.created_at ?? 0; - if (a.created_at > existingCreated) { + if (a.created_at > (existing?.created_at ?? 0)) { if (existing) { a.relays = dedupe([...existing.relays, ...a.relays]); } diff --git a/packages/system/src/outbox/index.ts b/packages/system/src/outbox/index.ts index 47500feb..3a31b93e 100644 --- a/packages/system/src/outbox/index.ts +++ b/packages/system/src/outbox/index.ts @@ -1,5 +1,5 @@ import { EventKind, FullRelaySettings, NostrEvent, SystemInterface, UsersRelays } from ".."; -import { sanitizeRelayUrl } from "@snort/shared"; +import { removeUndefined, sanitizeRelayUrl } from "@snort/shared"; export const DefaultPickNRelays = 2; @@ -20,6 +20,7 @@ export type EventFetcher = { }; export function parseRelayTag(tag: Array) { + if (tag[0] !== "r") return; return { url: sanitizeRelayUrl(tag[1]), settings: { @@ -30,7 +31,7 @@ export function parseRelayTag(tag: Array) { } export function parseRelayTags(tag: Array>) { - return tag.map(parseRelayTag).filter(a => a !== null); + return removeUndefined(tag.map(parseRelayTag)); } export function parseRelaysFromKind(ev: NostrEvent) { @@ -54,5 +55,21 @@ export function parseRelaysFromKind(ev: NostrEvent) { } } +/** + * Convert relay settings into NIP-65 relay tag + */ +export function settingsToRelayTag(rx: FullRelaySettings) { + const rTag = ["r", rx.url]; + if (rx.settings.read && !rx.settings.write) { + rTag.push("read"); + } + if (rx.settings.write && !rx.settings.read) { + rTag.push("write"); + } + if (rx.settings.read || rx.settings.write) { + return rTag; + } +} + export * from "./outbox-model"; export * from "./relay-loader"; diff --git a/packages/system/src/outbox/outbox-model.ts b/packages/system/src/outbox/outbox-model.ts index f1c25de5..4aedeea6 100644 --- a/packages/system/src/outbox/outbox-model.ts +++ b/packages/system/src/outbox/outbox-model.ts @@ -182,6 +182,16 @@ export class OutboxModel extends BaseRequestRouter { return ret; } + async forReplyTo(pk: string, pickN?: number | undefined): Promise { + const recipients = [pk]; + await this.updateRelayLists(recipients); + const relays = this.pickTopRelays(recipients, pickN ?? DefaultPickNRelays, "read"); + const ret = removeUndefined(dedupe(relays.map(a => a.relays).flat())); + + this.#log("Picked: pattern=%s, input=%s, output=%O", "inbox", pk, ret); + return ret; + } + /** * Update relay cache with latest relay lists * @param authors The authors to update relay lists for diff --git a/packages/system/src/query-manager.ts b/packages/system/src/query-manager.ts index 6a1d29c5..5c996aa1 100644 --- a/packages/system/src/query-manager.ts +++ b/packages/system/src/query-manager.ts @@ -4,6 +4,7 @@ import { BuiltRawReqFilter, RequestBuilder, SystemInterface, TaggedNostrEvent } import { Query, TraceReport } from "./query"; import { FilterCacheLayer } from "./filter-cache-layer"; import { trimFilters } from "./request-trim"; +import { eventMatchesFilter } from "./request-matcher"; interface QueryManagerEvents { change: () => void; @@ -75,26 +76,19 @@ export class QueryManager extends EventEmitter { * Async fetch results */ async fetch(req: RequestBuilder, cb?: (evs: Array) => void) { - const q = new Query(this.#system, req); - q.on("trace", r => this.emit("trace", r)); - q.on("request", (subId, fx) => { - this.#send(q, fx); - }); + const filters = req.buildRaw(); + const q = this.query(req); if (cb) { - q.on("event", evs => cb(evs)); + q.on("event", cb); } await new Promise(resolve => { - q.on("loading", loading => { - this.#log("loading %s %o", q.id, loading); - if (!loading) { - resolve(); - } - }); + q.once("done", resolve); }); const results = q.feed.takeSnapshot(); - q.cleanup(); - this.#log("Fetch results for %s %o", q.id, results); - return results; + if (cb) { + q.off("event", cb); + } + return results.filter(a => filters.some(b => eventMatchesFilter(a, b))); } *[Symbol.iterator]() { @@ -112,6 +106,7 @@ export class QueryManager extends EventEmitter { const data = await this.#system.cacheRelay.query(["REQ", q.id, ...qSend.filters]); if (data.length > 0) { qSend.syncFrom = data as Array; + this.#log("Adding from cache: %O", data); q.feed.add(data as Array); } } @@ -138,6 +133,8 @@ export class QueryManager extends EventEmitter { const qt = q.sendToRelay(s, qSend); if (qt) { return [qt]; + } else { + this.#log("Query not sent to %s: %O", qSend.relay, qSend); } } else { const nc = await this.#system.pool.connect(qSend.relay, { read: true, write: true }, true); @@ -145,6 +142,8 @@ export class QueryManager extends EventEmitter { const qt = q.sendToRelay(nc, qSend); if (qt) { return [qt]; + } else { + this.#log("Query not sent to %s: %O", qSend.relay, qSend); } } else { console.warn("Failed to connect to new relay for:", qSend.relay, q); @@ -158,6 +157,8 @@ export class QueryManager extends EventEmitter { const qt = q.sendToRelay(s, qSend); if (qt) { ret.push(qt); + } else { + this.#log("Query not sent to %s: %O", a, qSend); } } } diff --git a/packages/system/src/query.ts b/packages/system/src/query.ts index 94343bae..22f22c72 100644 --- a/packages/system/src/query.ts +++ b/packages/system/src/query.ts @@ -99,11 +99,11 @@ export interface TraceReport { } export interface QueryEvents { - loading: (v: boolean) => void; trace: (report: TraceReport) => void; request: (subId: string, req: BuiltRawReqFilter) => void; event: (evs: Array) => void; end: () => void; + done: () => void; } const QueryCache = new LRUCache>({ @@ -357,7 +357,7 @@ export class Query extends EventEmitter { const isFinished = this.progress === 1; if (isFinished) { this.#log("%s loading=%s, progress=%d, traces=%O", this.id, !isFinished, this.progress, this.#tracing); - this.emit("loading", !isFinished); + this.emit("done"); } } @@ -384,6 +384,10 @@ export class Query extends EventEmitter { if (q.relay && q.relay !== c.Address) { return false; } + // connection is down, dont send + if (c.isDown) { + return false; + } // cannot send unless relay is tagged on ephemeral relay connection if (!q.relay && c.Ephemeral) { this.#log("Cant send non-specific REQ to ephemeral connection %O %O %O", q, q.relay, c); diff --git a/packages/system/src/relay-info.ts b/packages/system/src/relay-info.ts index 106f57c6..5974eea9 100644 --- a/packages/system/src/relay-info.ts +++ b/packages/system/src/relay-info.ts @@ -18,4 +18,5 @@ export interface RelayInfo { language_tags?: Array; tags?: Array; posting_policy?: string; + negentropy?: string; } diff --git a/packages/system/src/request-builder.ts b/packages/system/src/request-builder.ts index cf4e6578..26344bfa 100644 --- a/packages/system/src/request-builder.ts +++ b/packages/system/src/request-builder.ts @@ -3,7 +3,7 @@ import { v4 as uuid } from "uuid"; import { appendDedupe, dedupe, removeUndefined, sanitizeRelayUrl, unixNowMs, unwrap } from "@snort/shared"; import EventKind from "./event-kind"; -import { FlatReqFilter, NostrLink, NostrPrefix, SystemInterface } from "."; +import { FlatReqFilter, NostrLink, NostrPrefix, SystemInterface, ToNostrEventTag } from "."; import { ReqFilter, u256, HexKey, TaggedNostrEvent } from "./nostr"; import { RequestRouter } from "./request-router"; @@ -230,6 +230,19 @@ export class RequestFilterBuilder { return this; } + /** + * Query by a nostr tag + */ + tags(tags: Array) { + for (const tag of tags) { + const tt = tag.toEventTag(); + if (tt) { + this.tag(tt[0], [tt[1]]); + } + } + return this; + } + search(keyword?: string) { if (!keyword) return this; this.#filter.search = keyword; diff --git a/packages/system/src/request-router.ts b/packages/system/src/request-router.ts index 973c454c..dd544764 100644 --- a/packages/system/src/request-router.ts +++ b/packages/system/src/request-router.ts @@ -6,6 +6,15 @@ import { FlatReqFilter } from "./query-optimizer"; * Request router managed splitting of requests to one or more relays, and which relay to send events to. */ export interface RequestRouter { + /** + * Pick relays to send an event to + * @param pk The pubkey you are replying to + * @param system Nostr system interface + * @param pickN Number of relays to pick per recipient + * @returns + */ + forReplyTo(pk: string, pickN?: number): Promise>; + /** * Pick relays to send an event to * @param ev The reply event to send @@ -39,6 +48,7 @@ export interface RequestRouter { } export abstract class BaseRequestRouter implements RequestRouter { + abstract forReplyTo(pk: string, pickN?: number): Promise>; abstract forReply(ev: NostrEvent, pickN?: number): Promise>; abstract forRequest(filter: ReqFilter, pickN?: number): Array; abstract forFlatRequest(filter: FlatReqFilter[], pickN?: number): Array; diff --git a/packages/system/src/signer.ts b/packages/system/src/signer.ts index b15bb378..31614a53 100644 --- a/packages/system/src/signer.ts +++ b/packages/system/src/signer.ts @@ -4,7 +4,7 @@ import { EventExt } from "./event-ext"; import { Nip4WebCryptoEncryptor } from "./impl/nip4"; import { XChaCha20Encryptor } from "./impl/nip44"; import { MessageEncryptorVersion, decodeEncryptionPayload, encodeEncryptionPayload } from "./index"; -import { NostrEvent } from "./nostr"; +import { NostrEvent, NotSignedNostrEvent } from "./nostr"; import { base64 } from "@scure/base"; export type SignerSupports = "nip04" | "nip44" | string; @@ -16,7 +16,7 @@ export interface EventSigner { nip4Decrypt(content: string, otherKey: string): Promise; nip44Encrypt(content: string, key: string): Promise; nip44Decrypt(content: string, otherKey: string): Promise; - sign(ev: NostrEvent): Promise; + sign(ev: NostrEvent | NotSignedNostrEvent): Promise; get supports(): Array; } diff --git a/packages/system/src/sync/diff-sync.ts b/packages/system/src/sync/diff-sync.ts index 9549bd55..c899d009 100644 --- a/packages/system/src/sync/diff-sync.ts +++ b/packages/system/src/sync/diff-sync.ts @@ -1,100 +1,210 @@ -import { EventBuilder, EventSigner, NostrLink, SystemInterface } from ".."; -import { SafeSync } from "./safe-sync"; +import { EventEmitter } from "eventemitter3"; +import { EventBuilder, EventSigner, NostrEvent, NostrLink, NotSignedNostrEvent, SystemInterface, Tag } from ".."; +import { SafeSync, SafeSyncEvents } from "./safe-sync"; import debug from "debug"; interface TagDiff { - type: "add" | "remove" | "replace"; + type: "add" | "remove" | "replace" | "update"; tag: Array | Array>; } /** * Add/Remove tags from event */ -export class DiffSyncTags { +export class DiffSyncTags extends EventEmitter { #log = debug("DiffSyncTags"); - #sync = new SafeSync(); + #sync: SafeSync; #changes: Array = []; + #changesEncrypted: Array = []; + #decryptedContent?: string; - constructor(readonly link: NostrLink) {} + constructor(readonly link: NostrLink) { + super(); + this.#sync = new SafeSync(link); + this.#sync.on("change", () => { + this.emit("change"); + }); + } + + /** + * Get the raw storage event + */ + get value() { + return this.#sync.value; + } + + /** + * Get the current tag set + */ + get tags() { + const next = this.#nextEvent(); + return next.tags; + } + + /** + * Get decrypted content + */ + get encryptedTags() { + if (this.#decryptedContent) { + const tags = JSON.parse(this.#decryptedContent) as Array>; + return tags; + } + return []; + } /** * Add a tag */ - add(tag: Array | Array>) { - this.#changes.push({ + add(tag: Array | Array>, encrypted = false) { + (encrypted ? this.#changesEncrypted : this.#changes).push({ type: "add", tag, }); + this.emit("change"); } /** * Remove a tag */ - remove(tag: Array | Array>) { - this.#changes.push({ + remove(tag: Array | Array>, encrypted = false) { + (encrypted ? this.#changesEncrypted : this.#changes).push({ type: "remove", tag, }); + this.emit("change"); + } + + /** + * Update a tag (remove+add) + */ + update(tag: Array | Array>, encrypted = false) { + (encrypted ? this.#changesEncrypted : this.#changes).push({ + type: "update", + tag, + }); + this.emit("change"); } /** * Replace all the tags */ - replace(tag: Array>) { - this.#changes.push({ + replace(tag: Array>, encrypted = false) { + (encrypted ? this.#changesEncrypted : this.#changes).push({ type: "replace", tag, }); + this.emit("change"); + } + + async sync(signer: EventSigner, system: SystemInterface) { + await this.#sync.sync(system); + + if ( + this.#sync.value?.content && + this.#sync.value?.content.startsWith("[") && + this.#sync.value?.content.endsWith("]") + ) { + const decrypted = await signer.nip4Decrypt(this.#sync.value.content, await signer.getPubKey()); + this.#decryptedContent = decrypted; + } } /** * Apply changes and save */ async persist(signer: EventSigner, system: SystemInterface, content?: string) { - const cloneChanges = [...this.#changes]; - this.#changes = []; + if (!this.#sync.didSync) { + await this.sync(signer, system); + } - // always start with sync - const res = await this.#sync.sync(this.link, system); + const isNew = this.#sync.value === undefined; + const next = this.#nextEvent(content); + // content is populated as tags, encrypt it + if (next.content.length > 0 && !content) { + next.content = await signer.nip4Encrypt(next.content, await signer.getPubKey()); + } + await this.#sync.update(next, signer, system, !isNew); + } + #nextEvent(content?: string): NotSignedNostrEvent { + if (content !== undefined && this.#changesEncrypted.length > 0) { + throw new Error("Cannot have both encrypted tags and explicit content"); + } let isNew = false; - let next = res ? { ...res } : undefined; + let next = this.#sync.value ? { ...this.#sync.value } : undefined; if (!next) { const eb = new EventBuilder(); eb.fromLink(this.link); next = eb.build(); isNew = true; } - if (content) { + + // apply changes onto next + this.#applyChanges(next.tags, this.#changes); + if (this.#changesEncrypted.length > 0 && !content) { + const encryptedTags = isNew ? [] : this.encryptedTags; + this.#applyChanges(encryptedTags, this.#changesEncrypted); + next.content = JSON.stringify(encryptedTags); + } else if (content) { next.content = content; } - // apply changes onto next - for (const change of cloneChanges) { - for (const changeTag of Array.isArray(change.tag[0]) - ? (change.tag as Array>) - : [change.tag as Array]) { - const existing = next.tags.findIndex(a => a.every((b, i) => changeTag[i] === b)); - switch (change.type) { - case "add": { + return next; + } + + #applyChanges(tags: Array>, changes: Array) { + for (const change of changes) { + if (change.tag.length === 0 && change.type !== "replace") continue; + + switch (change.type) { + case "add": { + const changeTags = Array.isArray(change.tag[0]) + ? (change.tag as Array>) + : [change.tag as Array]; + for (const changeTag of changeTags) { + const existing = tags.findIndex(a => change.tag[0] === a[0] && change.tag[1] === a[1]); if (existing === -1) { - next.tags.push(changeTag); + tags.push(changeTag); } else { this.#log("Tag already exists: %O", changeTag); } - break; } - case "remove": { + break; + } + case "remove": { + const changeTags = Array.isArray(change.tag[0]) + ? (change.tag as Array>) + : [change.tag as Array]; + for (const changeTag of changeTags) { + const existing = tags.findIndex(a => change.tag[0] === a[0] && change.tag[1] === a[1]); if (existing !== -1) { - next.tags.splice(existing, 1); + tags.splice(existing, 1); } else { this.#log("Could not find tag to remove: %O", changeTag); } } + break; + } + case "update": { + const changeTags = Array.isArray(change.tag[0]) + ? (change.tag as Array>) + : [change.tag as Array]; + for (const changeTag of changeTags) { + const existing = tags.findIndex(a => change.tag[0] === a[0] && change.tag[1] === a[1]); + if (existing !== -1) { + tags[existing] = changeTag; + } else { + this.#log("Could not find tag to update: %O", changeTag); + } + } + break; + } + case "replace": { + tags.splice(0, tags.length); + tags.push(...(change.tag as Array>)); + break; } } } - - await this.#sync.update(next, signer, system, !isNew); } } diff --git a/packages/system/src/sync/index.ts b/packages/system/src/sync/index.ts index a153f172..1cac5bbf 100644 --- a/packages/system/src/sync/index.ts +++ b/packages/system/src/sync/index.ts @@ -1,7 +1,3 @@ -export interface HasId { - id: string; -} - export * from "./safe-sync"; export * from "./range-sync"; export * from "./json-in-event-sync"; diff --git a/packages/system/src/sync/json-in-event-sync.ts b/packages/system/src/sync/json-in-event-sync.ts index 24702f10..0a20e74f 100644 --- a/packages/system/src/sync/json-in-event-sync.ts +++ b/packages/system/src/sync/json-in-event-sync.ts @@ -1,14 +1,9 @@ -import { SafeSync } from "./safe-sync"; -import { HasId } from "."; -import { EventBuilder, EventSigner, NostrEvent, NostrLink, NostrPrefix, SystemInterface } from ".."; +import { SafeSync, SafeSyncEvents } from "./safe-sync"; +import { EventBuilder, EventSigner, NostrEvent, NostrLink, SystemInterface } from ".."; import debug from "debug"; import EventEmitter from "eventemitter3"; -export interface JsonSyncEvents { - change: () => void; -} - -export class JsonEventSync extends EventEmitter { +export class JsonEventSync extends EventEmitter { #log = debug("JsonEventSync"); #sync: SafeSync; #json: T; @@ -19,7 +14,7 @@ export class JsonEventSync extends EventEmitter readonly encrypt: boolean, ) { super(); - this.#sync = new SafeSync(); + this.#sync = new SafeSync(link); this.#json = initValue; this.#sync.on("change", () => this.emit("change")); @@ -31,7 +26,7 @@ export class JsonEventSync extends EventEmitter } async sync(signer: EventSigner, system: SystemInterface) { - const res = await this.#sync.sync(this.link, system); + const res = await this.#sync.sync(system); this.#log("Sync result %O", res); if (res) { if (this.encrypt) { @@ -71,6 +66,5 @@ export class JsonEventSync extends EventEmitter await this.#sync.update(next, signer, system, !isNew); this.#json = val; - this.#json.id = next.id; } } diff --git a/packages/system/src/sync/safe-sync.ts b/packages/system/src/sync/safe-sync.ts index 14525728..42f547b2 100644 --- a/packages/system/src/sync/safe-sync.ts +++ b/packages/system/src/sync/safe-sync.ts @@ -1,5 +1,14 @@ import EventEmitter from "eventemitter3"; -import { EventExt, EventSigner, EventType, NostrEvent, NostrLink, RequestBuilder, SystemInterface } from ".."; +import { + EventExt, + EventSigner, + EventType, + NostrEvent, + NostrLink, + NotSignedNostrEvent, + RequestBuilder, + SystemInterface, +} from ".."; import { unixNow } from "@snort/shared"; import debug from "debug"; @@ -21,6 +30,10 @@ export class SafeSync extends EventEmitter { #base: NostrEvent | undefined; #didSync = false; + constructor(readonly link: NostrLink) { + super(); + } + get value() { return this.#base ? Object.freeze({ ...this.#base }) : undefined; } @@ -31,14 +44,13 @@ export class SafeSync extends EventEmitter { /** * Fetch the latest version - * @param link A link to the kind */ - async sync(link: NostrLink, system: SystemInterface) { - if (link.kind === undefined || link.author === undefined) { + async sync(system: SystemInterface) { + if (this.link.kind === undefined || this.link.author === undefined) { throw new Error("Kind must be set"); } - return await this.#sync(link, system); + return await this.#sync(system); } /** @@ -57,15 +69,23 @@ export class SafeSync extends EventEmitter { * Event will be signed again inside * @param ev */ - async update(next: NostrEvent, signer: EventSigner, system: SystemInterface, mustExist?: boolean) { - next.id = ""; - next.sig = ""; + async update( + next: NostrEvent | NotSignedNostrEvent, + signer: EventSigner, + system: SystemInterface, + mustExist?: boolean, + ) { + if ("sig" in next) { + next.id = ""; + next.sig = ""; + } + console.debug(this.#base, next); const signed = await this.#signEvent(next, signer); - const link = NostrLink.fromEvent(signed); + // always attempt to get a newer version before broadcasting - await this.#sync(link, system); + await this.#sync(system); this.#checkForUpdate(signed, mustExist ?? true); system.BroadcastEvent(signed); @@ -73,28 +93,21 @@ export class SafeSync extends EventEmitter { this.emit("change"); } - async #signEvent(next: NostrEvent, signer: EventSigner) { - next.created_at = unixNow(); - if (this.#base) { - const prevTag = next.tags.find(a => a[0] === "previous"); - if (prevTag) { - prevTag[1] = this.#base.id; - } else { - next.tags.push(["previous", this.#base.id]); - } - } - next.id = EventExt.createId(next); - return await signer.sign(next); + async #signEvent(next: NotSignedNostrEvent, signer: EventSigner) { + const toSign = { ...next, id: "", sig: "" } as NostrEvent; + toSign.created_at = unixNow(); + toSign.id = EventExt.createId(toSign); + return await signer.sign(toSign); } - async #sync(link: NostrLink, system: SystemInterface) { - const rb = new RequestBuilder(`sync:${link.encode()}`); - const f = rb.withFilter().link(link); + async #sync(system: SystemInterface) { + const rb = new RequestBuilder("sync"); + const f = rb.withFilter().link(this.link); if (this.#base) { f.since(this.#base.created_at); } const results = await system.Fetch(rb); - const res = results.find(a => link.matchesEvent(a)); + const res = results.find(a => this.link.matchesEvent(a)); this.#log("Got result %O", res); if (res && res.created_at > (this.#base?.created_at ?? 0)) { this.#base = res; diff --git a/packages/system/src/user-state.ts b/packages/system/src/user-state.ts new file mode 100644 index 00000000..17ee37a1 --- /dev/null +++ b/packages/system/src/user-state.ts @@ -0,0 +1,433 @@ +import { NostrPrefix } from "./links"; +import { NostrLink, ToNostrEventTag } from "./nostr-link"; +import { DiffSyncTags, JsonEventSync } from "./sync"; +import EventKind from "./event-kind"; +import { + EventSigner, + FullRelaySettings, + RelaySettings, + SystemInterface, + UserMetadata, + parseRelayTags, + parseRelaysFromKind, + settingsToRelayTag, +} from "."; +import { dedupe, removeUndefined, sanitizeRelayUrl } from "@snort/shared"; +import debug from "debug"; +import EventEmitter from "eventemitter3"; + +export interface UserStateOptions { + appdataId: string; + initAppdata: T; + encryptAppdata: boolean; +} + +/** + * Data which can be stored locally to quickly resume the state at startup + */ +export interface UserStateObject { + profile?: UserMetadata; + follows?: Array; + relays?: Array; + appdata?: TAppData; +} + +export const enum UserStateChangeType { + Profile, + Contacts, + Relays, + AppData, + MuteList, + GenericList, +} + +export interface UserStateEvents { + change: (t: UserStateChangeType) => void; +} + +/** + * Manages a users state, mostly to improve safe syncing + */ +export class UserState extends EventEmitter { + #log = debug("UserState"); + #profile: JsonEventSync; // kind 0 + #contacts: DiffSyncTags; // kind 3 + #relays: DiffSyncTags; // kind 10_003 + #appdata?: JsonEventSync; // kind 30_0078 + #standardLists: Map; // NIP-51 lists + + // init vars + #signer?: EventSigner; + #system?: SystemInterface; + + // state object will be used in the getters as a fallback value + #stateObj?: UserStateObject; + #didInit = false; + + constructor( + readonly pubkey: string, + options?: Partial>, + stateObj?: UserStateObject, + ) { + super(); + this.#stateObj = stateObj; + this.#standardLists = new Map(); + + this.#profile = new JsonEventSync( + undefined, + new NostrLink(NostrPrefix.Event, "", EventKind.SetMetadata, pubkey), + false, + ); + this.#contacts = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", EventKind.ContactList, pubkey)); + this.#relays = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", EventKind.Relays, pubkey)); + if (options?.appdataId && options.initAppdata) { + const link = new NostrLink(NostrPrefix.Address, options.appdataId, EventKind.AppData, pubkey); + this.#appdata = new JsonEventSync(options.initAppdata, link, options.encryptAppdata ?? false); + this.#appdata.on("change", () => this.emit("change", UserStateChangeType.AppData)); + } + + // always track mute list + this.#checkIsStandardList(EventKind.MuteList); + + this.#profile.on("change", () => this.emit("change", UserStateChangeType.Profile)); + this.#contacts.on("change", () => this.emit("change", UserStateChangeType.Contacts)); + this.#relays.on("change", () => this.emit("change", UserStateChangeType.Relays)); + } + + async init(signer: EventSigner, system: SystemInterface) { + if (this.#didInit) { + return; + } + this.#didInit = true; + this.#log("Init start"); + this.#signer = signer; + this.#system = system; + const tasks = [ + this.#profile.sync(signer, system), + this.#contacts.sync(signer, system), + this.#relays.sync(signer, system), + ]; + if (this.#appdata) { + tasks.push(this.#appdata.sync(signer, system)); + } + for (const list of this.#standardLists.values()) { + tasks.push(list.sync(signer, system)); + } + await Promise.all(tasks); + this.#log( + "Init results: profile=%O, contacts=%O, relays=%O, appdata=%O, lists=%O", + this.#profile.json, + this.#contacts.value, + this.#relays.value, + this.#appdata?.json, + [...this.#standardLists.values()].map(a => a.value), + ); + + // update relay metadata with value from contact list if not found + if (this.#relays.value === undefined && this.#contacts.value?.content !== undefined) { + this.#log("Saving relays to NIP-65 relay list using %O", this.relays); + for (const r of this.relays ?? []) { + await this.addRelay(r.url, r.settings, false); + } + + await this.#relays.persist(signer, system); + } + + // migrate mutes into blocks + const muteList = this.#standardLists.get(EventKind.MuteList); + if (muteList && muteList.tags.length > 0) { + this.#log("Migrating mutes into blocks mutes=%i, blocks=%i", muteList.tags.length, muteList.encryptedTags.length); + muteList.replace([], false); + muteList.add(muteList!.tags, true); + await muteList.persist(signer, system); + } + } + + /** + * Users profile + */ + get profile() { + return this.#profile.json ?? this.#stateObj?.profile; + } + + /** + * Users configured relays + */ + get relays() { + if (this.#relays.value) { + return parseRelayTags(this.#relays.tags); + } else if (this.#contacts.value) { + return parseRelaysFromKind(this.#contacts.value); + } else { + return this.#stateObj?.relays; + } + } + + /** + * Followed pubkeys + */ + get follows() { + if (this.#contacts.value) { + const pTags = this.#contacts.tags.filter(a => a[0] === "p" && a[1].length === 64).map(a => a[1]) ?? []; + return dedupe(pTags); + } else { + return this.#stateObj?.follows; + } + } + + /** + * App specific data + */ + get appdata() { + return this.#appdata?.json ?? this.#stateObj?.appdata; + } + + /** + * Get the standard mute list + */ + get muted() { + const list = this.#standardLists.get(EventKind.MuteList); + if (list) { + return NostrLink.fromTags(list.encryptedTags); + } + return []; + } + + async follow(link: NostrLink, autoCommit = false) { + this.#checkInit(); + if (link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey) { + throw new Error("Cannot follow this type of link"); + } + + const tag = link.toEventTag(); + if (tag) { + this.#contacts.add(tag); + if (autoCommit) { + await this.saveContacts(); + } + } else { + throw new Error("Invalid link"); + } + } + + async unfollow(link: NostrLink, autoCommit = false) { + this.#checkInit(); + if (link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey) { + throw new Error("Cannot follow this type of link"); + } + + const tag = link.toEventTag(); + if (tag) { + this.#contacts.remove(tag); + if (autoCommit) { + await this.saveContacts(); + } + } else { + throw new Error("Invalid link"); + } + } + + async replaceFollows(links: Array, autoCommit = false) { + this.#checkInit(); + if (links.some(link => link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey)) { + throw new Error("Cannot follow this type of link"); + } + + const tags = removeUndefined(links.map(link => link.toEventTag())); + this.#contacts.replace(tags); + if (autoCommit) { + await this.saveContacts(); + } + } + + /** + * Manually save contact list changes + * + * used with `autocommit = false` + */ + async saveContacts() { + this.#checkInit(); + const content = JSON.stringify(this.#relaysObject()); + await this.#contacts.persist(this.#signer!, this.#system!, content); + } + + async addRelay(addr: string, settings: RelaySettings, autoCommit = false) { + this.#checkInit(); + + const tag = settingsToRelayTag({ + url: addr, + settings, + }); + if (tag) { + this.#relays.add(tag); + if (autoCommit) { + await this.saveRelays(); + } + } else { + throw new Error("Invalid relay options"); + } + } + + async removeRelay(addr: string, autoCommit = false) { + this.#checkInit(); + + const url = sanitizeRelayUrl(addr); + if (url) { + this.#relays.remove(["r", url]); + if (autoCommit) { + await this.saveRelays(); + } + } else { + throw new Error("Invalid relay options"); + } + } + + async updateRelay(addr: string, settings: RelaySettings, autoCommit = false) { + this.#checkInit(); + + const tag = settingsToRelayTag({ + url: addr, + settings, + }); + const url = sanitizeRelayUrl(addr); + if (url && tag) { + this.#relays.update(tag); + if (autoCommit) { + await this.saveRelays(); + } + } else { + throw new Error("Invalid relay options"); + } + } + + /** + * Manually save relays + * + * used with `autocommit = false` + */ + async saveRelays() { + this.#checkInit(); + await this.#relays.persist(this.#signer!, this.#system!); + } + + async setAppData(data: TAppData) { + this.#checkInit(); + if (!this.#appdata) { + throw new Error("Not using appdata, please use options when constructing this class"); + } + + await this.#appdata.updateJson(data, this.#signer!, this.#system!); + } + + /** + * Add an item to the list + * @param kind List kind + * @param link Tag to save + * @param autoCommit Save after adding + * @param encrypted Tag is private and should be encrypted in the content + */ + async addToList( + kind: EventKind, + links: ToNostrEventTag | Array, + autoCommit = false, + encrypted = false, + ) { + this.#checkIsStandardList(kind); + this.#checkInit(); + const list = this.#standardLists.get(kind); + const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]); + if (list && tags.length > 0) { + list.add(tags, encrypted); + if (autoCommit) { + await this.saveList(kind); + } + } + } + + /** + * Remove an item to the list + * @param kind List kind + * @param link Tag to save + * @param autoCommit Save after adding + * @param encrypted Tag is private and should be encrypted in the content + */ + async removeFromList( + kind: EventKind, + links: ToNostrEventTag | Array, + autoCommit = false, + encrypted = false, + ) { + this.#checkIsStandardList(kind); + this.#checkInit(); + const list = this.#standardLists.get(kind); + const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]); + if (list && tags.length > 0) { + list.remove(tags, encrypted); + if (autoCommit) { + await this.saveList(kind); + } + } + } + + /** + * Manuall save list changes + * + * used with `autocommit = false` + */ + async saveList(kind: EventKind, content?: string) { + const list = this.#standardLists.get(kind); + await list?.persist(this.#signer!, this.#system!, content); + } + + async mute(link: NostrLink, autoCommit = false) { + await this.addToList(EventKind.MuteList, link, autoCommit, true); + } + + async unmute(link: NostrLink, autoCommit = false) { + await this.removeFromList(EventKind.MuteList, link, autoCommit, true); + } + + isOnList(kind: EventKind, link: ToNostrEventTag) { + const list = this.#standardLists.get(kind); + const tag = link.toEventTag(); + if (list && tag) { + return list.tags.some(a => a[0] === tag[0] && a[1] === tag[1]); + } + return false; + } + + getList(kind: EventKind): Array { + const list = this.#standardLists.get(kind); + return NostrLink.fromTags(list?.tags ?? []); + } + + serialize(): UserStateObject { + return { + profile: this.profile, + relays: this.relays, + follows: this.follows, + appdata: this.appdata, + }; + } + + #checkIsStandardList(kind: EventKind) { + if (!(kind >= 10_000 && kind < 20_000)) { + throw new Error("Not a standar list"); + } + if (!this.#standardLists.has(kind)) { + const list = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", kind, this.pubkey)); + list.on("change", () => this.emit("change", UserStateChangeType.GenericList)); + this.#standardLists.set(kind, list); + } + } + + #checkInit() { + if (this.#signer === undefined || this.#system === undefined) { + throw new Error("Please call init() first"); + } + } + + #relaysObject() { + return Object.fromEntries(this.relays?.map(a => [a.url, a.settings]) ?? []) as Record; + } +} diff --git a/packages/system/tests/Query.test.ts b/packages/system/tests/Query.test.ts index 9572c48b..34ed21c2 100644 --- a/packages/system/tests/Query.test.ts +++ b/packages/system/tests/Query.test.ts @@ -16,11 +16,8 @@ describe("query", () => { write: true, }; const c1 = new Connection("wss://one.com", opt); - c1.Down = false; const c2 = new Connection("wss://two.com", opt); - c2.Down = false; const c3 = new Connection("wss://three.com", opt); - c3.Down = false; const f = { relay: "", diff --git a/yarn.lock b/yarn.lock index f4cc1d11..efa26c7b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -65,6 +65,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.1, @babel/code-frame@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/code-frame@npm:7.24.2" + dependencies: + "@babel/highlight": "npm:^7.24.2" + picocolors: "npm:^1.0.0" + checksum: 10/7db8f5b36ffa3f47a37f58f61e3d130b9ecad21961f3eede7e2a4ac2c7e4a5efb6e9d03a810c669bc986096831b6c0dfc2c3082673d93351b82359c1b03e0590 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3": version: 7.23.3 resolution: "@babel/compat-data@npm:7.23.3" @@ -72,6 +82,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/compat-data@npm:7.24.4" + checksum: 10/e51faec0ac8259f03cc5029d2b4a944b4fee44cb5188c11530769d5beb81f384d031dba951febc3e33dbb48ceb8045b1184f5c1ac4c5f86ab1f5e951e9aaf7af + languageName: node + linkType: hard + "@babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.3": version: 7.23.3 resolution: "@babel/core@npm:7.23.3" @@ -95,6 +112,43 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.16.0": + version: 7.24.4 + resolution: "@babel/core@npm:7.24.4" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.24.2" + "@babel/generator": "npm:^7.24.4" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.24.4" + "@babel/parser": "npm:^7.24.4" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/1e049f8df26be0fe5be36173fd7c33dfb004eeeec28152fea83c90e71784f9a6f2237296f43a2ee7d9041e2a33a05f43da48ce2d4e0cd473a682328ca07ce7e0 + languageName: node + linkType: hard + +"@babel/eslint-parser@npm:^7.16.3": + version: 7.24.1 + resolution: "@babel/eslint-parser@npm:7.24.1" + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals": "npm:5.1.1-v1" + eslint-visitor-keys: "npm:^2.1.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 + checksum: 10/b65f93d880e4f3f62cb1d23a50139434b0e14b12acaeca40035d204a705f1ff0fbd191ed5101dd122473ba012dd3d08a3427960e4aab7fb384cfb3fc3f040a3e + languageName: node + linkType: hard + "@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.7.2": version: 7.23.3 resolution: "@babel/generator@npm:7.23.3" @@ -107,7 +161,19 @@ __metadata: languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.22.5": +"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/generator@npm:7.24.4" + dependencies: + "@babel/types": "npm:^7.24.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10/69e1772dcf8f95baec951f422cca091d59a3f29b5eedc989ad87f7262289b94625983f6fe654302ca17aae0a32f9232332b83fcc85533311d6267b09c58b1061 + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" dependencies: @@ -138,6 +204,38 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" + dependencies: + "@babel/compat-data": "npm:^7.23.5" + "@babel/helper-validator-option": "npm:^7.23.5" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/05595cd73087ddcd81b82d2f3297aac0c0422858dfdded43d304786cf680ec33e846e2317e6992d2c964ee61d93945cbf1fa8ec80b55aee5bfb159227fb02cb9 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.4" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-member-expression-to-functions": "npm:^7.23.0" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.24.1" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/86153719d98e4402f92f24d6b1be94e6b59c0236a6cc36b173a570a64b5156dbc2f16ccfe3c8485dc795524ca88acca65b14863be63049586668c45567f2acd4 + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.22.15": version: 7.22.15 resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" @@ -185,6 +283,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-define-polyfill-provider@npm:^0.6.1": + version: 0.6.1 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.1" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.22.6" + "@babel/helper-plugin-utils": "npm:^7.22.5" + debug: "npm:^4.1.1" + lodash.debounce: "npm:^4.0.8" + resolve: "npm:^1.14.2" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/316e7c0f05d2ae233d5fbb622c6339436da8d2b2047be866b64a16e6996c078a23b4adfebbdb33bc6a9882326a6cc20b95daa79a5e0edc92e9730e36d45fa523 + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.22.20, @babel/helper-environment-visitor@npm:^7.22.5": version: 7.22.20 resolution: "@babel/helper-environment-visitor@npm:7.22.20" @@ -211,7 +324,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.22.15": +"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" dependencies: @@ -229,6 +342,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.24.1, @babel/helper-module-imports@npm:^7.24.3": + version: 7.24.3 + resolution: "@babel/helper-module-imports@npm:7.24.3" + dependencies: + "@babel/types": "npm:^7.24.0" + checksum: 10/42fe124130b78eeb4bb6af8c094aa749712be0f4606f46716ce74bc18a5ea91c918c547c8bb2307a2e4b33f163e4ad2cb6a7b45f80448e624eae45b597ea3499 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -260,6 +382,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: 10/dc8c7af321baf7653d93315beffee1790eb2c464b4f529273a24c8743a3f3095bf3f2d11828cb2c52d56282ef43a4bdc67a79c9ab8dd845e35d01871f3f28a0e + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" @@ -286,6 +415,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/helper-replace-supers@npm:7.24.1" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-member-expression-to-functions": "npm:^7.23.0" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/1103b28ce0cc7fba903c21bc78035c696ff191bdbbe83c20c37030a2e10ae6254924556d942cdf8c44c48ba606a8266fdb105e6bb10945de9285f79cb1905df1 + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-simple-access@npm:7.22.5" @@ -295,7 +437,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" dependencies: @@ -320,6 +462,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.24.1 + resolution: "@babel/helper-string-parser@npm:7.24.1" + checksum: 10/04c0ede77b908b43e6124753b48bc485528112a9335f0a21a226bff1ace75bb6e64fab24c85cb4b1610ef3494dacd1cb807caeb6b79a7b36c43d48c289b35949 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" @@ -334,6 +483,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 10/537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-wrap-function@npm:7.22.20" @@ -356,6 +512,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/helpers@npm:7.24.4" + dependencies: + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + checksum: 10/54a9d0f86f2803fcc216cfa23b66b871ea0fa0a892af1c9a79075872c2437de71afbb150ed8216f30e00b19a0b9c5c9d5845173d170e1ebfbbf8887839b89dde + languageName: node + linkType: hard + "@babel/highlight@npm:^7.22.13": version: 7.22.20 resolution: "@babel/highlight@npm:7.22.20" @@ -367,6 +534,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/highlight@npm:7.24.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/4555124235f34403bb28f55b1de58edf598491cc181c75f8afc8fe529903cb598cd52fe3bf2faab9bc1f45c299681ef0e44eea7a848bb85c500c5a4fe13f54f6 + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.3": version: 7.23.3 resolution: "@babel/parser@npm:7.23.3" @@ -376,6 +555,27 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1, @babel/parser@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/parser@npm:7.24.4" + bin: + parser: ./bin/babel-parser.js + checksum: 10/3742cc5068036287e6395269dce5a2735e6349cdc8d4b53297c75f98c580d7e1c8cb43235623999d151f2ef975d677dbc2c2357573a1855caa71c271bf3046c9 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/1439e2ceec512b72f05f036503bf2c31e807d1b75ae22cf2676145e9f20740960a1c9575ea3065c6fb9f44f6b46163aab76eac513694ffa10de674e3cdd6219e + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.23.3" @@ -387,6 +587,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/ec5fddc8db6de0e0082a883f21141d6f4f9f9f0bc190d662a732b5e9a506aae5d7d2337049a1bf055d7cb7add6f128036db6d4f47de5e9ac1be29e043c8b7ca8 + languageName: node + linkType: hard + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.23.3" @@ -400,6 +611,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.13.0 + checksum: 10/e18235463e716ac2443938aaec3c18b40c417a1746fba0fa4c26cf4d71326b76ef26c002081ab1b445abfae98e063d561519aa55672dddc1ef80b3940211ffbb + languageName: node + linkType: hard + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.23.3" @@ -412,6 +636,92 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.1" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/3483f329bb099b438d05e5e206229ddbc1703972a69ba0240a796b5477369930b0ab2e7f6c9539ecad2cea8b0c08fa65498778b92cf87ad3d156f613de1fd2fa + languageName: node + linkType: hard + +"@babel/plugin-proposal-class-properties@npm:^7.16.0": + version: 7.18.6 + resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 + languageName: node + linkType: hard + +"@babel/plugin-proposal-decorators@npm:^7.16.4": + version: 7.24.1 + resolution: "@babel/plugin-proposal-decorators@npm:7.24.1" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-decorators": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/cbc489ae3ebe5216a4d764a6d155591282e819b6b7436c4cffbb8f123515a1db9cc2f84259c36d558f896e8ff8526ebd28d3563fabb04347ae1964c476b44b9f + languageName: node + linkType: hard + +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.16.0": + version: 7.18.6 + resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d + languageName: node + linkType: hard + +"@babel/plugin-proposal-numeric-separator@npm:^7.16.0": + version: 7.18.6 + resolution: "@babel/plugin-proposal-numeric-separator@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.18.6" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec + languageName: node + linkType: hard + +"@babel/plugin-proposal-optional-chaining@npm:^7.16.0": + version: 7.21.0 + resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.20.2" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.20.0" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/522cd133aff5c94c0ef36ff83c64f03deee183815da68b65b6950e81972ace3b514e032df07ea76d0f9ec8cc7a49578092907adfa17fccb4612117557c04a882 + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-methods@npm:^7.16.0": + version: 7.18.6 + resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad + languageName: node + linkType: hard + "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": version: 7.21.0-placeholder-for-preset-env.2 resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" @@ -421,6 +731,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-private-property-in-object@npm:^7.16.7": + version: 7.21.11 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.11" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.18.6" + "@babel/helper-create-class-features-plugin": "npm:^7.21.0" + "@babel/helper-plugin-utils": "npm:^7.20.2" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f803b5e1de0cb7c53f0d7f70bfbf57f2b3a20d95c19f8f2710719c4938149b490ee14d2d0c2f8316080823f0943c6cb8668fa8c139420e7bc7f80a66bfd50fff + languageName: node + linkType: hard + "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -465,6 +789,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-decorators@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-decorators@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/6e70d64b6ce6843dd388740eef032c5a013b6b873e3a6ccdb41f342b91b49d4dac1ce5daac32f588c66815047ce00bab0785a8a45d724e6dce9f49bff01fb24e + languageName: node + linkType: hard + "@babel/plugin-syntax-dynamic-import@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" @@ -487,6 +822,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-flow@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-flow@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/87dfe32f3a3ea77941034fb2a39fdfc9ea18a994b8df40c3659a11c8787b2bc5adea029259c4eafc03cd35f11628f6533aa2a06381db7fcbe3b2cc3c2a2bb54f + languageName: node + linkType: hard + "@babel/plugin-syntax-import-assertions@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-syntax-import-assertions@npm:7.23.3" @@ -498,6 +844,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-import-assertions@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/2a463928a63b62052e9fb8f8b0018aa11a926e94f32c168260ae012afe864875c6176c6eb361e13f300542c31316dad791b08a5b8ed92436a3095c7a0e4fce65 + languageName: node + linkType: hard + "@babel/plugin-syntax-import-attributes@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-syntax-import-attributes@npm:7.23.3" @@ -509,6 +866,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-import-attributes@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/87c8aa4a5ef931313f956871b27f2c051556f627b97ed21e9a5890ca4906b222d89062a956cde459816f5e0dec185ff128d7243d3fdc389504522acb88f0464e + languageName: node + linkType: hard + "@babel/plugin-syntax-import-meta@npm:^7.10.4, @babel/plugin-syntax-import-meta@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" @@ -531,6 +899,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-jsx@npm:^7.23.3, @babel/plugin-syntax-jsx@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/712f7e7918cb679f106769f57cfab0bc99b311032665c428b98f4c3e2e6d567601d45386a4f246df6a80d741e1f94192b3f008800d66c4f1daae3ad825c243f0 + languageName: node + linkType: hard + "@babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.23.3 resolution: "@babel/plugin-syntax-jsx@npm:7.23.3" @@ -630,6 +1009,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-typescript@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-typescript@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/bf4bd70788d5456b5f75572e47a2e31435c7c4e43609bd4dffd2cc0c7a6cf90aabcf6cd389e351854de9a64412a07d30effef5373251fe8f6a4c9db0c0163bda + languageName: node + linkType: hard + "@babel/plugin-syntax-typescript@npm:^7.7.2": version: 7.23.3 resolution: "@babel/plugin-syntax-typescript@npm:7.23.3" @@ -664,6 +1054,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-arrow-functions@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/58f9aa9b0de8382f8cfa3f1f1d40b69d98cd2f52340e2391733d0af745fdddda650ba392e509bc056157c880a2f52834a38ab2c5aa5569af8c61bb6ecbf45f34 + languageName: node + linkType: hard + "@babel/plugin-transform-async-generator-functions@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.3" @@ -678,6 +1079,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-generator-functions@npm:^7.24.3": + version: 7.24.3 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.3" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-remap-async-to-generator": "npm:^7.22.20" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4ccc3755a3d51544cd43575db2c5c2ef42cdcd35bd5940d13cdf23f04c75496290e79ea585a62427ec6bd508a1bffb329e01556cd1114be9b38ae4254935cd19 + languageName: node + linkType: hard + "@babel/plugin-transform-async-to-generator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3" @@ -691,6 +1106,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-to-generator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.1" + dependencies: + "@babel/helper-module-imports": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-remap-async-to-generator": "npm:^7.22.20" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/429004a6596aa5c9e707b604156f49a146f8d029e31a3152b1649c0b56425264fda5fd38e5db1ddaeb33c3fe45c97dc8078d7abfafe3542a979b49f229801135 + languageName: node + linkType: hard + "@babel/plugin-transform-block-scoped-functions@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.23.3" @@ -702,6 +1130,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-block-scoped-functions@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d8e18bd57b156da1cd4d3c1780ab9ea03afed56c6824ca8e6e74f67959d7989a0e953ec370fe9b417759314f2eef30c8c437395ce63ada2e26c2f469e4704f82 + languageName: node + linkType: hard + "@babel/plugin-transform-block-scoping@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-block-scoping@npm:7.23.3" @@ -713,6 +1152,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-block-scoping@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/plugin-transform-block-scoping@npm:7.24.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4093fa109cd256e8ad0b26e3ffa67ec6dac4078a1a24b7755bed63e650cf938b2a315e01696c35b221db1a37606f93cb82696c8d1bf563c2a9845620e551736e + languageName: node + linkType: hard + "@babel/plugin-transform-class-properties@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-class-properties@npm:7.23.3" @@ -725,6 +1175,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-class-properties@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-class-properties@npm:7.24.1" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/95779e9eef0c0638b9631c297d48aee53ffdbb2b1b5221bf40d7eccd566a8e34f859ff3571f8f20b9159b67f1bff7d7dc81da191c15d69fbae5a645197eae7e0 + languageName: node + linkType: hard + "@babel/plugin-transform-class-static-block@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-class-static-block@npm:7.23.3" @@ -738,6 +1200,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-class-static-block@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.4" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.4" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 10/3b1db3308b57ba21d47772a9f183804234c23fd64c9ca40915d2d65c5dc7a48b49a6de16b8b90b7a354eacbb51232a862f0fca3dbd23e27d34641f511decddab + languageName: node + linkType: hard + "@babel/plugin-transform-classes@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-classes@npm:7.23.3" @@ -757,6 +1232,24 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-classes@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-classes@npm:7.24.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-replace-supers": "npm:^7.24.1" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + globals: "npm:^11.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/eb7f4a3d852cfa20f4efd299929c564bd2b45106ac1cf4ac8b0c87baf078d4a15c39b8a21bbb01879c1922acb9baaf3c9b150486e18d84b30129e9671639793d + languageName: node + linkType: hard + "@babel/plugin-transform-computed-properties@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-computed-properties@npm:7.23.3" @@ -769,6 +1262,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-computed-properties@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-computed-properties@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/template": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/62bbfe1bd508517d96ba6909e68b1adb9dfd24ea61af1f4b0aa909bfc5e476044afe9c55b10ef74508fd147aa665e818df67ece834d164a9fd69b80c9ede3875 + languageName: node + linkType: hard + "@babel/plugin-transform-destructuring@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-destructuring@npm:7.23.3" @@ -780,6 +1285,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-destructuring@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/03d9a81cd9eeb24d48e207be536d460d6ad228238ac70da9b7ad4bae799847bb3be0aecfa4ea6223752f3a8d4ada3a58cd9a0f8fc70c01fdfc87ad0618f897d3 + languageName: node + linkType: hard + "@babel/plugin-transform-dotall-regex@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-dotall-regex@npm:7.23.3" @@ -792,6 +1308,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-dotall-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/7f623d25b6f213b94ebc1754e9e31c1077c8e288626d8b7bfa76a97b067ce80ddcd0ede402a546706c65002c0ccf45cd5ec621511c2668eed31ebcabe8391d35 + languageName: node + linkType: hard + "@babel/plugin-transform-duplicate-keys@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-duplicate-keys@npm:7.23.3" @@ -803,6 +1331,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-duplicate-keys@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/de600a958ad146fc8aca71fd2dfa5ebcfdb97df4eaa530fc9a4b0d28d85442ddb9b7039f260b396785211e88c6817125a94c183459763c363847e8c84f318ff0 + languageName: node + linkType: hard + "@babel/plugin-transform-dynamic-import@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.3" @@ -815,6 +1354,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-dynamic-import@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/59fc561ee40b1a69f969c12c6c5fac206226d6642213985a569dd0f99f8e41c0f4eaedebd36936c255444a8335079842274c42a975a433beadb436d4c5abb79b + languageName: node + linkType: hard + "@babel/plugin-transform-exponentiation-operator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.23.3" @@ -827,6 +1378,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-exponentiation-operator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.1" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f90841fe1a1e9f680b4209121d3e2992f923e85efcd322b26e5901c180ef44ff727fb89790803a23fac49af34c1ce2e480018027c22b4573b615512ac5b6fc50 + languageName: node + linkType: hard + "@babel/plugin-transform-export-namespace-from@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.3" @@ -839,6 +1402,30 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-export-namespace-from@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/bc710ac231919df9555331885748385c11c5e695d7271824fe56fba51dd637d48d3e5cd52e1c69f2b1a384fbbb41552572bc1ca3a2285ee29571f002e9bb2421 + languageName: node + linkType: hard + +"@babel/plugin-transform-flow-strip-types@npm:^7.16.0": + version: 7.24.1 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-flow": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/6e1db557d7d34a8dbfdf430557f47c75930a9044b838bb3cc706f9c816e11cd68a61c68239478dd05bbe3ec197113ad0c22c5be1bdddac8723040dd9e9cb9dc0 + languageName: node + linkType: hard + "@babel/plugin-transform-for-of@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-for-of@npm:7.23.3" @@ -850,6 +1437,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-for-of@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-for-of@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/befd0908c3f6b31f9fa9363a3c112d25eaa0bc4a79cfad1f0a8bb5010937188b043a44fb23443bc8ffbcc40c015bb25f80e4cc585ce5cc580708e2d56e76fe37 + languageName: node + linkType: hard + "@babel/plugin-transform-function-name@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-function-name@npm:7.23.3" @@ -863,6 +1462,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-function-name@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-function-name@npm:7.24.1" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/31eb3c75297dda7265f78eba627c446f2324e30ec0124a645ccc3e9f341254aaa40d6787bd62b2280d77c0a5c9fbfce1da2c200ef7c7f8e0a1b16a8eb3644c6f + languageName: node + linkType: hard + "@babel/plugin-transform-json-strings@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-json-strings@npm:7.23.3" @@ -875,6 +1487,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-json-strings@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f42302d42fc81ac00d14e9e5d80405eb80477d7f9039d7208e712d6bcd486a4e3b32fdfa07b5f027d6c773723d8168193ee880f93b0e430c828e45f104fb82a4 + languageName: node + linkType: hard + "@babel/plugin-transform-literals@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-literals@npm:7.23.3" @@ -886,6 +1510,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-literals@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-literals@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/2df94e9478571852483aca7588419e574d76bde97583e78551c286f498e01321e7dbb1d0ef67bee16e8f950688f79688809cfde370c5c4b84c14d841a3ef217a + languageName: node + linkType: hard + "@babel/plugin-transform-logical-assignment-operators@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.3" @@ -898,6 +1533,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/895f2290adf457cbf327428bdb4fb90882a38a22f729bcf0629e8ad66b9b616d2721fbef488ac00411b647489d1dda1d20171bb3772d0796bb7ef5ecf057808a + languageName: node + linkType: hard + "@babel/plugin-transform-member-expression-literals@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.23.3" @@ -909,6 +1556,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-member-expression-literals@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4ea641cc14a615f9084e45ad2319f95e2fee01c77ec9789685e7e11a6c286238a426a98f9c1ed91568a047d8ac834393e06e8c82d1ff01764b7aa61bee8e9023 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-amd@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-amd@npm:7.23.3" @@ -921,6 +1579,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-amd@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-modules-amd@npm:7.24.1" + dependencies: + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/5a324f7c630cf0be1f09098a3a36248c2521622f2c7ea1a44a5980f54b718f5e0dd4af92a337f4b445a8824c8d533853ebea7c16de829b8a7bc8bcca127d4d73 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-commonjs@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.3" @@ -934,6 +1604,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-commonjs@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.1" + dependencies: + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-simple-access": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/7326a62ed5f766f93ee75684868635b59884e2801533207ea11561c296de53037949fecad4055d828fa7ebeb6cc9e55908aa3e7c13f930ded3e62ad9f24680d7 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-systemjs@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3" @@ -948,6 +1631,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-systemjs@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.1" + dependencies: + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-identifier": "npm:^7.22.20" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/565ec4518037b3d957431e29bda97b3d2fbb2e245fb5ba19889310ccb8fb71353e8ce2c325cc8d3fbc5a376d3af7d7e21782d5f502c46f8da077bee7807a590f + languageName: node + linkType: hard + "@babel/plugin-transform-modules-umd@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3" @@ -960,6 +1657,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-umd@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-modules-umd@npm:7.24.1" + dependencies: + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/323bb9367e1967117a829f67788ec2ff55504b4faf8f6d83ec85d398e50b41cf7d1c375c67d63883dd7ad5e75b35c8ae776d89e422330ec0c0a1fda24e362083 + languageName: node + linkType: hard + "@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" @@ -983,6 +1692,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-new-target@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-new-target@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e0d3af66cd0fad29c9d0e3fc65e711255e18b77e2e35bbd8f10059e3db7de6c16799ef74e704daf784950feb71e7a93c5bf2c771d98f1ca3fba1ff2e0240b24a + languageName: node + linkType: hard + "@babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.3" @@ -995,6 +1715,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/74025e191ceb7cefc619c15d33753aab81300a03d81b96ae249d9b599bc65878f962d608f452462d3aad5d6e334b7ab2b09a6bdcfe8d101fe77ac7aacca4261e + languageName: node + linkType: hard + "@babel/plugin-transform-numeric-separator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.3" @@ -1007,6 +1739,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-numeric-separator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3247bd7d409574fc06c59e0eb573ae7470d6d61ecf780df40b550102bb4406747d8f39dcbec57eb59406df6c565a86edd3b429e396ad02e4ce201ad92050832e + languageName: node + linkType: hard + "@babel/plugin-transform-object-rest-spread@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.3" @@ -1022,6 +1766,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-object-rest-spread@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.1" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-transform-parameters": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ff6eeefbc5497cf33d62dc86b797c6db0e9455d6a4945d6952f3b703d04baab048974c6573b503e0ec097b8112d3b98b5f4ee516e1b8a74ed47aebba4d9d2643 + languageName: node + linkType: hard + "@babel/plugin-transform-object-super@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-object-super@npm:7.23.3" @@ -1034,6 +1792,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-object-super@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-object-super@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-replace-supers": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d34d437456a54e2a5dcb26e9cf09ed4c55528f2a327c5edca92c93e9483c37176e228d00d6e0cf767f3d6fdbef45ae3a5d034a7c59337a009e20ae541c8220fa + languageName: node + linkType: hard + "@babel/plugin-transform-optional-catch-binding@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.3" @@ -1046,6 +1816,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ff7c02449d32a6de41e003abb38537b4a1ad90b1eaa4c0b578cb1b55548201a677588a8c47f3e161c72738400ae811a6673ea7b8a734344755016ca0ac445dac + languageName: node + linkType: hard + "@babel/plugin-transform-optional-chaining@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.3" @@ -1059,6 +1841,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-optional-chaining@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d41031b8e472b9b30aacd905a1561904bcec597dd888ad639b234971714dc9cd0dcb60df91a89219fc72e4feeb148e20f97bcddc39d7676e743ff0c23f62a7eb + languageName: node + linkType: hard + "@babel/plugin-transform-parameters@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-parameters@npm:7.23.3" @@ -1070,6 +1865,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-parameters@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-parameters@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/c289c188710cd1c60991db169d8173b6e8e05624ae61a7da0b64354100bfba9e44bc1332dd9223c4e3fe1b9cbc0c061e76e7c7b3a75c9588bf35d0ffec428070 + languageName: node + linkType: hard + "@babel/plugin-transform-private-methods@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-private-methods@npm:7.23.3" @@ -1082,6 +1888,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-private-methods@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-private-methods@npm:7.24.1" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/7208c30bb3f3fbc73fb3a88bdcb78cd5cddaf6d523eb9d67c0c04e78f6fc6319ece89f4a5abc41777ceab16df55b3a13a4120e0efc9275ca6d2d89beaba80aa0 + languageName: node + linkType: hard + "@babel/plugin-transform-private-property-in-object@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.3" @@ -1096,6 +1914,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-private-property-in-object@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-create-class-features-plugin": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/466d1943960c2475c0361eba2ea72d504d4d8329a8e293af0eedd26887bf30a074515b330ea84be77331ace77efbf5533d5f04f8cff63428d2615f4a509ae7a4 + languageName: node + linkType: hard + "@babel/plugin-transform-property-literals@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-property-literals@npm:7.23.3" @@ -1107,6 +1939,39 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-property-literals@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-property-literals@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a73646d7ecd95b3931a3ead82c7d5efeb46e68ba362de63eb437d33531f294ec18bd31b6d24238cd3b6a3b919a6310c4a0ba4a2629927721d4d10b0518eb7715 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-display-name@npm:^7.16.0, @babel/plugin-transform-react-display-name@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-react-display-name@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4cc7268652bd73a9e249db006d7278e3e90c033684e59801012311536f1ff93eb63fea845325035533aa281e428e6ec2ae0ad04659893ec1318250ddcf4a2f77 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx-self@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-react-jsx-self@npm:7.23.3" @@ -1129,6 +1994,33 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx@npm:^7.22.5, @babel/plugin-transform-react-jsx@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-react-jsx@npm:7.23.4" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/plugin-syntax-jsx": "npm:^7.23.3" + "@babel/types": "npm:^7.23.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d83806701349addfb77b8347b4f0dc8e76fb1c9ac21bdef69f4002394fce2396d61facfc6e1a3de54cbabcdadf991a1f642e69edb5116ac14f95e33d9f7c221d + languageName: node + linkType: hard + +"@babel/plugin-transform-react-pure-annotations@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/06a6bfe80f1f36408d07dd80c48cf9f61177c8e5d814e80ddbe88cfad81a8b86b3110e1fe9d1ac943db77e74497daa7f874b5490c788707106ad26ecfbe44813 + languageName: node + linkType: hard + "@babel/plugin-transform-regenerator@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-regenerator@npm:7.23.3" @@ -1141,6 +2033,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-regenerator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-regenerator@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + regenerator-transform: "npm:^0.15.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a04319388a0a7931c3f8e15715d01444c32519692178b70deccc86d53304e74c0f589a4268f6c68578d86f75e934dd1fe6e6ed9071f54ee8379f356f88ef6e42 + languageName: node + linkType: hard + "@babel/plugin-transform-reserved-words@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-reserved-words@npm:7.23.3" @@ -1152,6 +2056,33 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-reserved-words@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-reserved-words@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/132c6040c65aabae2d98a39289efb5c51a8632546dc50d2ad032c8660aec307fbed74ef499856ea4f881fc8505905f49b48e0270585da2ea3d50b75e962afd89 + languageName: node + linkType: hard + +"@babel/plugin-transform-runtime@npm:^7.16.4": + version: 7.24.3 + resolution: "@babel/plugin-transform-runtime@npm:7.24.3" + dependencies: + "@babel/helper-module-imports": "npm:^7.24.3" + "@babel/helper-plugin-utils": "npm:^7.24.0" + babel-plugin-polyfill-corejs2: "npm:^0.4.10" + babel-plugin-polyfill-corejs3: "npm:^0.10.1" + babel-plugin-polyfill-regenerator: "npm:^0.6.1" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/7f545c628993b527ae1cb028106168ec29873160a5d98aed947509b61e826fa52b6e2bd2c56504b4a5084555becc9841fa7842e61f822a050dd6ff5baff726ce + languageName: node + linkType: hard + "@babel/plugin-transform-shorthand-properties@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.23.3" @@ -1163,6 +2094,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-shorthand-properties@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/006a2032d1c57dca76579ce6598c679c2f20525afef0a36e9d42affe3c8cf33c1427581ad696b519cc75dfee46c5e8ecdf0c6a29ffb14250caa3e16dd68cb424 + languageName: node + linkType: hard + "@babel/plugin-transform-spread@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-spread@npm:7.23.3" @@ -1175,6 +2117,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-spread@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-spread@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/0b60cfe2f700ec2c9c1af979bb805860258539648dadcd482a5ddfc2330b733fb61bb60266404f3e068246ad0d6376040b4f9c5ab9037a3d777624d64acd89e9 + languageName: node + linkType: hard + "@babel/plugin-transform-sticky-regex@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-sticky-regex@npm:7.23.3" @@ -1186,6 +2140,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-sticky-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e326e96a9eeb6bb01dbc4d3362f989411490671b97f62edf378b8fb102c463a018b777f28da65344d41b22aa6efcdfa01ed43d2b11fdcf202046d3174be137c5 + languageName: node + linkType: hard + "@babel/plugin-transform-template-literals@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-template-literals@npm:7.23.3" @@ -1197,6 +2162,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-template-literals@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-template-literals@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4c9009c72321caf20e3b6328bbe9d7057006c5ae57b794cf247a37ca34d87dfec5e27284169a16df5a6235a083bf0f3ab9e1bfcb005d1c8b75b04aed75652621 + languageName: node + linkType: hard + "@babel/plugin-transform-typeof-symbol@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-typeof-symbol@npm:7.23.3" @@ -1208,6 +2184,31 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typeof-symbol@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3dda5074abf8b5df9cdef697d6ebe14a72c199bd6c2019991d033d9ad91b0be937b126b8f34c3c5a9725afee9016a3776aeef3e3b06ab9b3f54f2dd5b5aefa37 + languageName: node + linkType: hard + +"@babel/plugin-transform-typescript@npm:^7.24.1": + version: 7.24.4 + resolution: "@babel/plugin-transform-typescript@npm:7.24.4" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-create-class-features-plugin": "npm:^7.24.4" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-typescript": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e8d66fbafd6cbfeca2ebe77c4fc67537be9e01813f835ce097fa91329b0cd7ba587a9cf4c4a1df661cdde438741cb3c63d2ab95c97354eb89d7682a4d99bea5d + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-escapes@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3" @@ -1219,6 +2220,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-escapes@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d39041ff6b0cef78271ebe88be6dfd2882a3c6250a54ddae783f1b9adc815e8486a7d0ca054fabfa3fde1301c531d5be89224999fc7be83ff1eda9b77d173051 + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-property-regex@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.23.3" @@ -1231,6 +2243,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/276099b4483e707f80b054e2d29bc519158bfe52461ef5ff76f70727d592df17e30b1597ef4d8a0f04d810f6cb5a8dd887bdc1d0540af3744751710ef280090f + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-regex@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-unicode-regex@npm:7.23.3" @@ -1243,6 +2267,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/400a0927bdb1425b4c0dc68a61b5b2d7d17c7d9f0e07317a1a6a373c080ef94be1dd65fdc4ac9a78fcdb58f89fd128450c7bc0d5b8ca0ae7eca3fbd98e50acba + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-sets-regex@npm:^7.23.3": version: 7.23.3 resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.23.3" @@ -1255,6 +2291,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/364342fb8e382dfaa23628b88e6484dc1097e53fb7199f4d338f1e2cd71d839bb0a35a9b1380074f6a10adb2e98b79d53ca3ec78c0b8c557ca895ffff42180df + languageName: node + linkType: hard + "@babel/preset-env@npm:^7.11.0": version: 7.23.3 resolution: "@babel/preset-env@npm:7.23.3" @@ -1345,6 +2393,97 @@ __metadata: languageName: node linkType: hard +"@babel/preset-env@npm:^7.16.4": + version: 7.24.4 + resolution: "@babel/preset-env@npm:7.24.4" + dependencies: + "@babel/compat-data": "npm:^7.24.4" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.4" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1" + "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" + "@babel/plugin-syntax-import-assertions": "npm:^7.24.1" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.1" + "@babel/plugin-syntax-import-meta": "npm:^7.10.4" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.1" + "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.1" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1" + "@babel/plugin-transform-block-scoping": "npm:^7.24.4" + "@babel/plugin-transform-class-properties": "npm:^7.24.1" + "@babel/plugin-transform-class-static-block": "npm:^7.24.4" + "@babel/plugin-transform-classes": "npm:^7.24.1" + "@babel/plugin-transform-computed-properties": "npm:^7.24.1" + "@babel/plugin-transform-destructuring": "npm:^7.24.1" + "@babel/plugin-transform-dotall-regex": "npm:^7.24.1" + "@babel/plugin-transform-duplicate-keys": "npm:^7.24.1" + "@babel/plugin-transform-dynamic-import": "npm:^7.24.1" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.1" + "@babel/plugin-transform-export-namespace-from": "npm:^7.24.1" + "@babel/plugin-transform-for-of": "npm:^7.24.1" + "@babel/plugin-transform-function-name": "npm:^7.24.1" + "@babel/plugin-transform-json-strings": "npm:^7.24.1" + "@babel/plugin-transform-literals": "npm:^7.24.1" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.1" + "@babel/plugin-transform-member-expression-literals": "npm:^7.24.1" + "@babel/plugin-transform-modules-amd": "npm:^7.24.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.1" + "@babel/plugin-transform-modules-systemjs": "npm:^7.24.1" + "@babel/plugin-transform-modules-umd": "npm:^7.24.1" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" + "@babel/plugin-transform-new-target": "npm:^7.24.1" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.1" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.1" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.1" + "@babel/plugin-transform-object-super": "npm:^7.24.1" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.1" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.1" + "@babel/plugin-transform-parameters": "npm:^7.24.1" + "@babel/plugin-transform-private-methods": "npm:^7.24.1" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.1" + "@babel/plugin-transform-property-literals": "npm:^7.24.1" + "@babel/plugin-transform-regenerator": "npm:^7.24.1" + "@babel/plugin-transform-reserved-words": "npm:^7.24.1" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.1" + "@babel/plugin-transform-spread": "npm:^7.24.1" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.1" + "@babel/plugin-transform-template-literals": "npm:^7.24.1" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.1" + "@babel/plugin-transform-unicode-escapes": "npm:^7.24.1" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.1" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.1" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.1" + "@babel/preset-modules": "npm:0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2: "npm:^0.4.10" + babel-plugin-polyfill-corejs3: "npm:^0.10.4" + babel-plugin-polyfill-regenerator: "npm:^0.6.1" + core-js-compat: "npm:^3.31.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3d5cbdc2501bc1959fc76ed9d409d0ee5264bc475fa809958fd2e8e7db9b12f8eccdae750a0e05d25207373c42ca115b42bb3d5c743bc770cb12b6af05bf3bd8 + languageName: node + linkType: hard + "@babel/preset-modules@npm:0.1.6-no-external-plugins": version: 0.1.6-no-external-plugins resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" @@ -1358,6 +2497,37 @@ __metadata: languageName: node linkType: hard +"@babel/preset-react@npm:^7.16.0": + version: 7.24.1 + resolution: "@babel/preset-react@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-transform-react-display-name": "npm:^7.24.1" + "@babel/plugin-transform-react-jsx": "npm:^7.23.4" + "@babel/plugin-transform-react-jsx-development": "npm:^7.22.5" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a796c609ace7d58a56b42b6630cdd9e1d896ce2f8b35331b9ea040eaaf3cc9aa99cd2614e379a27c10410f34e89355e2739c7097e8065ce5e40900a77b13d716 + languageName: node + linkType: hard + +"@babel/preset-typescript@npm:^7.16.0": + version: 7.24.1 + resolution: "@babel/preset-typescript@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-syntax-jsx": "npm:^7.24.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.1" + "@babel/plugin-transform-typescript": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ba774bd427c9f376769ddbc2723f5801a6b30113a7c3aaa14c36215508e347a527fdae98cfc294f0ecb283d800ee0c1f74e66e38e84c9bc9ed2fe6ed50dcfaf8 + languageName: node + linkType: hard + "@babel/regjsgen@npm:^0.8.0": version: 0.8.0 resolution: "@babel/regjsgen@npm:0.8.0" @@ -1374,6 +2544,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.23.2": + version: 7.24.4 + resolution: "@babel/runtime@npm:7.24.4" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10/8ec8ce2c145bc7e31dd39ab66df124f357f65c11489aefacb30f431bae913b9aaa66aa5efe5321ea2bf8878af3fcee338c87e7599519a952e3a6f83aa1b03308 + languageName: node + linkType: hard + "@babel/template@npm:^7.22.15, @babel/template@npm:^7.3.3": version: 7.22.15 resolution: "@babel/template@npm:7.22.15" @@ -1385,6 +2564,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/template@npm:7.24.0" + dependencies: + "@babel/code-frame": "npm:^7.23.5" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10/8c538338c7de8fac8ada691a5a812bdcbd60bd4a4eb5adae2cc9ee19773e8fb1a724312a00af9e1ce49056ffd3c3475e7287b5668cf6360bfb3f8ac827a06ffe + languageName: node + linkType: hard + "@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.3": version: 7.23.3 resolution: "@babel/traverse@npm:7.23.3" @@ -1403,6 +2593,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/traverse@npm:7.24.1" + dependencies: + "@babel/code-frame": "npm:^7.24.1" + "@babel/generator": "npm:^7.24.1" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/parser": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/b9b0173c286ef549e179f3725df3c4958069ad79fe5b9840adeb99692eb4a5a08db4e735c0f086aab52e7e08ec711cee9e7c06cb908d8035641d1382172308d3 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.23.3 resolution: "@babel/types@npm:7.23.3" @@ -1414,6 +2622,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.23.4, @babel/types@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: 10/a0b4875ce2e132f9daff0d5b27c7f4c4fcc97f2b084bdc5834e92c9d32592778489029e65d99d00c406da612d87b72d7a236c0afccaa1435c028d0c94c9b6da4 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -2197,7 +3416,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" checksum: 10/8c36169c815fc5d726078e8c71a5b592957ee60d08c6470f9ce0187c8046af1a00afbda0a065cc40ff18d5d83f82aed9793c6818f7304a74a7488dc9f3ecbd42 @@ -2660,6 +3879,17 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10/81587b3c4dd8e6c60252122937cea0c637486311f4ed208b52b62aae2e7a87598f63ec330e6cd0984af494bfb16d3f0d60d3b21d7e5b4aedd2602ff3fe9d32e2 + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" @@ -2674,6 +3904,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10/832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 + languageName: node + linkType: hard + "@jridgewell/source-map@npm:^0.3.3": version: 0.3.5 resolution: "@jridgewell/source-map@npm:0.3.5" @@ -2711,6 +3948,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10/dced32160a44b49d531b80a4a2159dceab6b3ddf0c8e95a0deae4b0e894b172defa63d5ac52a19c2068e1fe7d31ea4ba931fbeec103233ecb4208953967120fc + languageName: node + linkType: hard + "@lightninglabs/lnc-core@npm:0.3.1-alpha": version: 0.3.1-alpha resolution: "@lightninglabs/lnc-core@npm:0.3.1-alpha" @@ -2728,6 +3975,15 @@ __metadata: languageName: node linkType: hard +"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": + version: 5.1.1-v1 + resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" + dependencies: + eslint-scope: "npm:5.1.1" + checksum: 10/f2e3b2d6a6e2d9f163ca22105910c9f850dc4897af0aea3ef0a5886b63d8e1ba6505b71c99cb78a3bba24a09557d601eb21c8dede3f3213753fcfef364eb0e57 + languageName: node + linkType: hard + "@noble/ciphers@npm:0.2.0": version: 0.2.0 resolution: "@noble/ciphers@npm:0.2.0" @@ -2944,6 +4200,16 @@ __metadata: languageName: node linkType: hard +"@rollup/pluginutils@npm:^4.2.1": + version: 4.2.1 + resolution: "@rollup/pluginutils@npm:4.2.1" + dependencies: + estree-walker: "npm:^2.0.1" + picomatch: "npm:^2.2.2" + checksum: 10/503a6f0a449e11a2873ac66cfdfb9a3a0b77ffa84c5cad631f5e4bc1063c850710e8d5cd5dab52477c0d66cda2ec719865726dbe753318cd640bab3fff7ca476 + languageName: node + linkType: hard + "@rollup/rollup-android-arm-eabi@npm:4.14.1": version: 4.14.1 resolution: "@rollup/rollup-android-arm-eabi@npm:4.14.1" @@ -3133,6 +4399,13 @@ __metadata: languageName: node linkType: hard +"@rushstack/eslint-patch@npm:^1.1.0": + version: 1.10.2 + resolution: "@rushstack/eslint-patch@npm:1.10.2" + checksum: 10/a92563ee28aa903ee37f5d34c747a8f5641c0a5a7020881902da8fccf94e208c923ed708aef41989f4b1d328cb4c216166ab108c6c2d72ebf0b5b6c18d1461d0 + languageName: node + linkType: hard + "@scure/base@npm:1.1.1": version: 1.1.1 resolution: "@scure/base@npm:1.1.1" @@ -3279,6 +4552,7 @@ __metadata: dexie: "npm:^3.2.4" emojilib: "npm:^3.0.10" eslint: "npm:^8.48.0" + eslint-config-react-app: "npm:^7.0.1" eslint-plugin-formatjs: "npm:^4.11.3" eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" @@ -3317,6 +4591,7 @@ __metadata: use-sync-external-store: "npm:^1.2.0" uuid: "npm:^9.0.0" vite: "npm:^5.2.8" + vite-plugin-eslint: "npm:^1.8.1" vite-plugin-pwa: "npm:^0.19.2" vite-plugin-version-mark: "npm:^0.0.10" vitest: "npm:^0.34.6" @@ -3863,6 +5138,16 @@ __metadata: languageName: node linkType: hard +"@types/eslint@npm:^8.4.5": + version: 8.56.9 + resolution: "@types/eslint@npm:8.56.9" + dependencies: + "@types/estree": "npm:*" + "@types/json-schema": "npm:*" + checksum: 10/fde20e8f3e5384f0ac78897b04cbaf1c78f4ba6cbdae9aeba876c00b665b498670cfcdf84a39eb4e44a6e27d6de80e24b5833d51a09d5d7e410229feb8b9c401 + languageName: node + linkType: hard + "@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.1": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" @@ -3942,7 +5227,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7 @@ -3956,6 +5241,13 @@ __metadata: languageName: node linkType: hard +"@types/json5@npm:^0.0.29": + version: 0.0.29 + resolution: "@types/json5@npm:0.0.29" + checksum: 10/4e5aed58cabb2bbf6f725da13421aa50a49abb6bc17bfab6c31b8774b073fa7b50d557c61f961a09a85f6056151190f8ac95f13f5b48136ba5841f7d4484ec56 + languageName: node + linkType: hard + "@types/latlon-geohash@npm:^2.0.3": version: 2.0.3 resolution: "@types/latlon-geohash@npm:2.0.3" @@ -4011,6 +5303,13 @@ __metadata: languageName: node linkType: hard +"@types/parse-json@npm:^4.0.0": + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: 10/5bf62eec37c332ad10059252fc0dab7e7da730764869c980b0714777ad3d065e490627be9f40fc52f238ffa3ac4199b19de4127196910576c2fe34dd47c7a470 + languageName: node + linkType: hard + "@types/parse-torrent-file@npm:*": version: 4.0.6 resolution: "@types/parse-torrent-file@npm:4.0.6" @@ -4081,6 +5380,13 @@ __metadata: languageName: node linkType: hard +"@types/semver@npm:^7.3.12": + version: 7.5.8 + resolution: "@types/semver@npm:7.5.8" + checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 + languageName: node + linkType: hard + "@types/semver@npm:^7.5.0": version: 7.5.5 resolution: "@types/semver@npm:7.5.5" @@ -4211,6 +5517,30 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:^5.5.0": + version: 5.62.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/type-utils": "npm:5.62.0" + "@typescript-eslint/utils": "npm:5.62.0" + debug: "npm:^4.3.4" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.2.0" + natural-compare-lite: "npm:^1.4.0" + semver: "npm:^7.3.7" + tsutils: "npm:^3.21.0" + peerDependencies: + "@typescript-eslint/parser": ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/9cc8319c6fd8a21938f5b69476974a7e778c283a55ef9fad183c850995b9adcb0087d57cea7b2ac6b9449570eee983aad39491d14cdd2e52d6b4b0485e7b2482 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^6.1.0": version: 6.11.0 resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0" @@ -4236,6 +5566,34 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/experimental-utils@npm:^5.0.0": + version: 5.62.0 + resolution: "@typescript-eslint/experimental-utils@npm:5.62.0" + dependencies: + "@typescript-eslint/utils": "npm:5.62.0" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10/ce55d9f74eac5cb94d66d5db9ead9a5d734f4301519fb5956a57f4b405a5318a115b0316195a3c039e0111489138680411709cb769085d71e1e1db1376ea0949 + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:^5.5.0": + version: 5.62.0 + resolution: "@typescript-eslint/parser@npm:5.62.0" + dependencies: + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/typescript-estree": "npm:5.62.0" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/b6ca629d8f4e6283ff124501731cc886703eb4ce2c7d38b3e4110322ea21452b9d9392faf25be6bd72f54b89de7ffc72a40d9b159083ac54345a3d04b4fa5394 + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:^6.1.0": version: 6.11.0 resolution: "@typescript-eslint/parser@npm:6.11.0" @@ -4254,6 +5612,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/scope-manager@npm:5.62.0" + dependencies: + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/visitor-keys": "npm:5.62.0" + checksum: 10/e827770baa202223bc0387e2fd24f630690809e460435b7dc9af336c77322290a770d62bd5284260fa881c86074d6a9fd6c97b07382520b115f6786b8ed499da + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/scope-manager@npm:6.11.0" @@ -4264,6 +5632,23 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/type-utils@npm:5.62.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:5.62.0" + "@typescript-eslint/utils": "npm:5.62.0" + debug: "npm:^4.3.4" + tsutils: "npm:^3.21.0" + peerDependencies: + eslint: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/f9a4398d6d2aae09e3e765eff04cf4ab364376a87868031ac5c6a64c9bbb555cb1a7f99b07b3d1017e7422725b5f0bbee537f13b82ab2d930f161c987b3dece0 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/type-utils@npm:6.11.0" @@ -4281,6 +5666,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/types@npm:5.62.0" + checksum: 10/24e8443177be84823242d6729d56af2c4b47bfc664dd411a1d730506abf2150d6c31bdefbbc6d97c8f91043e3a50e0c698239dcb145b79bb6b0c34469aaf6c45 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/types@npm:6.11.0" @@ -4288,6 +5680,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" + dependencies: + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/visitor-keys": "npm:5.62.0" + debug: "npm:^4.3.4" + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + semver: "npm:^7.3.7" + tsutils: "npm:^3.21.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/06c975eb5f44b43bd19fadc2e1023c50cf87038fe4c0dd989d4331c67b3ff509b17fa60a3251896668ab4d7322bdc56162a9926971218d2e1a1874d2bef9a52e + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/typescript-estree@npm:6.11.0" @@ -4306,6 +5716,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.58.0": + version: 5.62.0 + resolution: "@typescript-eslint/utils@npm:5.62.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@types/json-schema": "npm:^7.0.9" + "@types/semver": "npm:^7.3.12" + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/typescript-estree": "npm:5.62.0" + eslint-scope: "npm:^5.1.1" + semver: "npm:^7.3.7" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10/15ef13e43998a082b15f85db979f8d3ceb1f9ce4467b8016c267b1738d5e7cdb12aa90faf4b4e6dd6486c236cf9d33c463200465cf25ff997dbc0f12358550a1 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:6.11.0, @typescript-eslint/utils@npm:^6.5.0": version: 6.11.0 resolution: "@typescript-eslint/utils@npm:6.11.0" @@ -4323,6 +5751,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" + dependencies: + "@typescript-eslint/types": "npm:5.62.0" + eslint-visitor-keys: "npm:^3.3.0" + checksum: 10/dc613ab7569df9bbe0b2ca677635eb91839dfb2ca2c6fa47870a5da4f160db0b436f7ec0764362e756d4164e9445d49d5eb1ff0b87f4c058946ae9d8c92eb388 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:6.11.0": version: 6.11.0 resolution: "@typescript-eslint/visitor-keys@npm:6.11.0" @@ -4712,6 +6150,16 @@ __metadata: languageName: node linkType: hard +"array-buffer-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "array-buffer-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.5" + is-array-buffer: "npm:^3.0.4" + checksum: 10/53524e08f40867f6a9f35318fafe467c32e45e9c682ba67b11943e167344d2febc0f6977a17e699b05699e805c3e8f073d876f8bbf1b559ed494ad2cd0fae09e + languageName: node + linkType: hard + "array-includes@npm:^3.1.6": version: 3.1.7 resolution: "array-includes@npm:3.1.7" @@ -4725,6 +6173,20 @@ __metadata: languageName: node linkType: hard +"array-includes@npm:^3.1.7": + version: 3.1.8 + resolution: "array-includes@npm:3.1.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + is-string: "npm:^1.0.7" + checksum: 10/290b206c9451f181fb2b1f79a3bf1c0b66bb259791290ffbada760c79b284eef6f5ae2aeb4bcff450ebc9690edd25732c4c73a3c2b340fcc0f4563aed83bf488 + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -4732,7 +6194,35 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.3.1": +"array.prototype.findlast@npm:^1.2.4": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10/7dffcc665aa965718ad6de7e17ac50df0c5e38798c0a5bf9340cf24feb8594df6ec6f3fcbe714c1577728a1b18b5704b15669474b27bceeca91ef06ce2a23c31 + languageName: node + linkType: hard + +"array.prototype.findlastindex@npm:^1.2.3": + version: 1.2.5 + resolution: "array.prototype.findlastindex@npm:1.2.5" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10/7c5c821f357cd53ab6cc305de8086430dd8d7a2485db87b13f843e868055e9582b1fd338f02338f67fc3a1603ceaf9610dd2a470b0b506f9d18934780f95b246 + languageName: node + linkType: hard + +"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2": version: 1.3.2 resolution: "array.prototype.flat@npm:1.3.2" dependencies: @@ -4744,7 +6234,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.1": +"array.prototype.flatmap@npm:^1.3.1, array.prototype.flatmap@npm:^1.3.2": version: 1.3.2 resolution: "array.prototype.flatmap@npm:1.3.2" dependencies: @@ -4756,6 +6246,18 @@ __metadata: languageName: node linkType: hard +"array.prototype.toreversed@npm:^1.1.2": + version: 1.1.2 + resolution: "array.prototype.toreversed@npm:1.1.2" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + es-shim-unscopables: "npm:^1.0.0" + checksum: 10/b4076d687ddc22c191863ce105d320cc4b0e1435bfda9ffeeff681682fe88fa6fe30e0d2ae94fa4b2d7fad901e1954ea4f75c1cab217db4848da84a2b5889192 + languageName: node + linkType: hard + "array.prototype.tosorted@npm:^1.1.1": version: 1.1.2 resolution: "array.prototype.tosorted@npm:1.1.2" @@ -4769,6 +6271,19 @@ __metadata: languageName: node linkType: hard +"array.prototype.tosorted@npm:^1.1.3": + version: 1.1.3 + resolution: "array.prototype.tosorted@npm:1.1.3" + dependencies: + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.1.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10/9a5b7909a9ddd02a5f5489911766c314a11fb40f8f5106bdbedf6c21898763faeb78ba3af53f7038f288de9161d2605ad10d8b720e07f71a7ed1de49f39c0897 + languageName: node + linkType: hard + "arraybuffer.prototype.slice@npm:^1.0.2": version: 1.0.2 resolution: "arraybuffer.prototype.slice@npm:1.0.2" @@ -4784,6 +6299,22 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.3": + version: 1.0.3 + resolution: "arraybuffer.prototype.slice@npm:1.0.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.2.1" + get-intrinsic: "npm:^1.2.3" + is-array-buffer: "npm:^3.0.4" + is-shared-array-buffer: "npm:^1.0.2" + checksum: 10/0221f16c1e3ec7b67da870ee0e1f12b825b5f9189835392b59a22990f715827561a4f4cd5330dc7507de272d8df821be6cd4b0cb569babf5ea4be70e365a2f3d + languageName: node + linkType: hard + "asn1js@npm:^3.0.1, asn1js@npm:^3.0.5": version: 3.0.5 resolution: "asn1js@npm:3.0.5" @@ -4802,6 +6333,13 @@ __metadata: languageName: node linkType: hard +"ast-types-flow@npm:^0.0.8": + version: 0.0.8 + resolution: "ast-types-flow@npm:0.0.8" + checksum: 10/85a1c24af4707871c27cfe456bd2ff7fcbe678f3d1c878ac968c9557735a171a17bdcc8c8f903ceab3fc3c49d5b3da2194e6ab0a6be7fec0e133fa028f21ba1b + languageName: node + linkType: hard + "async@npm:^3.2.3": version: 3.2.5 resolution: "async@npm:3.2.5" @@ -4857,6 +6395,22 @@ __metadata: languageName: node linkType: hard +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10/6c9da3a66caddd83c875010a1ca8ef11eac02ba15fb592dc9418b2b5e7b77b645fa7729380a92d9835c2f05f2ca1b6251f39b993e0feb3f1517c74fa1af02cab + languageName: node + linkType: hard + +"axe-core@npm:=4.7.0": + version: 4.7.0 + resolution: "axe-core@npm:4.7.0" + checksum: 10/615c0f7722c3c9fcf353dbd70b00e2ceae234d4c17cbc839dd85c01d16797c4e4da45f8d27c6118e9e6b033fb06efd196106e13651a1b2f3a10e0f11c7b2f660 + languageName: node + linkType: hard + "axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" @@ -4908,6 +6462,30 @@ __metadata: languageName: node linkType: hard +"babel-plugin-macros@npm:^3.1.0": + version: 3.1.0 + resolution: "babel-plugin-macros@npm:3.1.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + cosmiconfig: "npm:^7.0.0" + resolve: "npm:^1.19.0" + checksum: 10/30be6ca45e9a124c58ca00af9a0753e5410ec0b79a737714fc4722bbbeb693e55d9258f05c437145ef4a867c2d1603e06a1c292d66c243ce1227458c8ea2ca8c + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs2@npm:^0.4.10": + version: 0.4.10 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.10" + dependencies: + "@babel/compat-data": "npm:^7.22.6" + "@babel/helper-define-polyfill-provider": "npm:^0.6.1" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/9fb5e59a3235eba66fb05060b2a3ecd6923084f100df7526ab74b6272347d7adcf99e17366b82df36e592cde4e82fdb7ae24346a990eced76c7d504cac243400 + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs2@npm:^0.4.6": version: 0.4.6 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6" @@ -4921,6 +6499,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.10.1, babel-plugin-polyfill-corejs3@npm:^0.10.4": + version: 0.10.4 + resolution: "babel-plugin-polyfill-corejs3@npm:0.10.4" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.1" + core-js-compat: "npm:^3.36.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/a69ed5a95bb55e9b7ea37307d56113f7e24054d479c15de6d50fa61388b5334bed1f9b6414cde6c575fa910a4de4d1ab4f2d22720967d57c4fec9d1b8f61b355 + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs3@npm:^0.8.5": version: 0.8.6 resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6" @@ -4944,6 +6534,24 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-regenerator@npm:^0.6.1": + version: 0.6.1 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.1" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/9df4a8e9939dd419fed3d9ea26594b4479f2968f37c225e1b2aa463001d7721f5537740e6622909d2a570b61cec23256924a1701404fc9d6fd4474d3e845cedb + languageName: node + linkType: hard + +"babel-plugin-transform-react-remove-prop-types@npm:^0.4.24": + version: 0.4.24 + resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.24" + checksum: 10/4ce1755af02375f0764683f9703ef47607e33ee57cefd348f054208e06a52b1517e43180c1c448046338a149853f2c9d7f63f27d5b27c74db5df74fba117f040 + languageName: node + linkType: hard + "babel-preset-current-node-syntax@npm:^1.0.0": version: 1.0.1 resolution: "babel-preset-current-node-syntax@npm:1.0.1" @@ -4978,6 +6586,30 @@ __metadata: languageName: node linkType: hard +"babel-preset-react-app@npm:^10.0.1": + version: 10.0.1 + resolution: "babel-preset-react-app@npm:10.0.1" + dependencies: + "@babel/core": "npm:^7.16.0" + "@babel/plugin-proposal-class-properties": "npm:^7.16.0" + "@babel/plugin-proposal-decorators": "npm:^7.16.4" + "@babel/plugin-proposal-nullish-coalescing-operator": "npm:^7.16.0" + "@babel/plugin-proposal-numeric-separator": "npm:^7.16.0" + "@babel/plugin-proposal-optional-chaining": "npm:^7.16.0" + "@babel/plugin-proposal-private-methods": "npm:^7.16.0" + "@babel/plugin-transform-flow-strip-types": "npm:^7.16.0" + "@babel/plugin-transform-react-display-name": "npm:^7.16.0" + "@babel/plugin-transform-runtime": "npm:^7.16.4" + "@babel/preset-env": "npm:^7.16.4" + "@babel/preset-react": "npm:^7.16.0" + "@babel/preset-typescript": "npm:^7.16.0" + "@babel/runtime": "npm:^7.16.3" + babel-plugin-macros: "npm:^3.1.0" + babel-plugin-transform-react-remove-prop-types: "npm:^0.4.24" + checksum: 10/ce66970267cfa6d6289b7bf070f184b3ece4f66fbdcd098c40573e3e86b42ffde7d16d74eabb0d18dc5960ddd3d943a16fac27c8dbb435f63350d6af1acbb28b + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -5062,6 +6694,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.22.2, browserslist@npm:^4.23.0": + version: 4.23.0 + resolution: "browserslist@npm:4.23.0" + dependencies: + caniuse-lite: "npm:^1.0.30001587" + electron-to-chromium: "npm:^1.4.668" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.0.13" + bin: + browserslist: cli.js + checksum: 10/496c3862df74565dd942b4ae65f502c575cbeba1fa4a3894dad7aa3b16130dc3033bc502d8848147f7b625154a284708253d9598bcdbef5a1e34cf11dc7bad8e + languageName: node + linkType: hard + "bs-logger@npm:0.x": version: 0.2.6 resolution: "bs-logger@npm:0.2.6" @@ -5142,6 +6788,19 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.1" + checksum: 10/cd6fe658e007af80985da5185bff7b55e12ef4c2b6f41829a26ed1eef254b1f1c12e3dfd5b2b068c6ba8b86aba62390842d81752e67dcbaec4f6f76e7113b6b7 + languageName: node + linkType: hard + "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -5177,6 +6836,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001587": + version: 1.0.30001610 + resolution: "caniuse-lite@npm:1.0.30001610" + checksum: 10/64370faefcb95cac8c95d7e4a90bf5ce45c25a59f186a9f84e88664a4a03c337119c15309c5fa3a2a7963fa2a7308c86a3b2335c92375314d684ad6aa46522ba + languageName: node + linkType: hard + "chai@npm:^4.3.10": version: 4.3.10 resolution: "chai@npm:4.3.10" @@ -5406,6 +7072,13 @@ __metadata: languageName: node linkType: hard +"confusing-browser-globals@npm:^1.0.11": + version: 1.0.11 + resolution: "confusing-browser-globals@npm:1.0.11" + checksum: 10/3afc635abd37e566477f610e7978b15753f0e84025c25d49236f1f14d480117185516bdd40d2a2167e6bed8048641a9854964b9c067e3dcdfa6b5d0ad3c3a5ef + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -5429,6 +7102,15 @@ __metadata: languageName: node linkType: hard +"core-js-compat@npm:^3.36.1": + version: 3.36.1 + resolution: "core-js-compat@npm:3.36.1" + dependencies: + browserslist: "npm:^4.23.0" + checksum: 10/d86b46805de7f5ba3675ed21532ecc64b6c1f123be7286b9efa7941ec087cd8d2446cb555f03a407dbbbeb6e881d1baf92eaffb7f051b11d9103f39c8731fa62 + languageName: node + linkType: hard + "cors@npm:~2.8.5": version: 2.8.5 resolution: "cors@npm:2.8.5" @@ -5439,6 +7121,19 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^7.0.0": + version: 7.1.0 + resolution: "cosmiconfig@npm:7.1.0" + dependencies: + "@types/parse-json": "npm:^4.0.0" + import-fresh: "npm:^3.2.1" + parse-json: "npm:^5.0.0" + path-type: "npm:^4.0.0" + yaml: "npm:^1.10.0" + checksum: 10/03600bb3870c80ed151b7b706b99a1f6d78df8f4bdad9c95485072ea13358ef294b13dd99f9e7bf4cc0b43bcd3599d40df7e648750d21c2f6817ca2cd687e071 + languageName: node + linkType: hard + "create-jest@npm:^29.7.0": version: 29.7.0 resolution: "create-jest@npm:29.7.0" @@ -5728,6 +7423,13 @@ __metadata: languageName: node linkType: hard +"damerau-levenshtein@npm:^1.0.8": + version: 1.0.8 + resolution: "damerau-levenshtein@npm:1.0.8" + checksum: 10/f4eba1c90170f96be25d95fa3857141b5f81e254f7e4d530da929217b19990ea9a0390fc53d3c1cafac9152fda78e722ea4894f765cf6216be413b5af1fbf821 + languageName: node + linkType: hard + "data-joint@npm:1": version: 1.3.1 resolution: "data-joint@npm:1.3.1" @@ -5748,7 +7450,40 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2": +"data-view-buffer@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-buffer@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/5919a39a18ee919573336158fd162fdf8ada1bc23a139f28543fd45fac48e0ea4a3ad3bfde91de124d4106e65c4a7525f6a84c20ba0797ec890a77a96d13a82a + languageName: node + linkType: hard + +"data-view-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/f33c65e58d8d0432ad79761f2e8a579818d724b5dc6dc4e700489b762d963ab30873c0f1c37d8f2ed12ef51c706d1195f64422856d25f067457aeec50cc40aac + languageName: node + linkType: hard + +"data-view-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "data-view-byte-offset@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10/96f34f151bf02affb7b9f98762fb7aca1dd5f4553cb57b80bce750ca609c15d33ca659568ef1d422f7e35680736cbccb893a3d4b012760c758c1446bbdc4c6db + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -5760,6 +7495,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:^3.2.7": + version: 3.2.7 + resolution: "debug@npm:3.2.7" + dependencies: + ms: "npm:^2.1.1" + checksum: 10/d86fd7be2b85462297ea16f1934dc219335e802f629ca9a69b63ed8ed041dda492389bb2ee039217c02e5b54792b1c51aa96ae954cf28634d363a2360c7a1639 + languageName: node + linkType: hard + "decimal.js-light@npm:^2.4.1": version: 2.5.1 resolution: "decimal.js-light@npm:2.5.1" @@ -5820,6 +7564,17 @@ __metadata: languageName: node linkType: hard +"define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10/abdcb2505d80a53524ba871273e5da75e77e52af9e15b3aa65d8aad82b8a3a424dad7aee2cc0b71470ac7acf501e08defac362e8b6a73cdb4309f028061df4ae + languageName: node + linkType: hard + "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" @@ -5964,6 +7719,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.668": + version: 1.4.737 + resolution: "electron-to-chromium@npm:1.4.737" + checksum: 10/3f6bceb069edd11ac4438d24fd261c38325b1afffaf447a7abec8a2f1942cf768cde141384f7cf25718b77330a9e5b29a5bd1c2927f07ac3f0d58cfbdcf9a0cc + languageName: node + linkType: hard + "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" @@ -6110,6 +7872,76 @@ __metadata: languageName: node linkType: hard +"es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.2": + version: 1.23.3 + resolution: "es-abstract@npm:1.23.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + arraybuffer.prototype.slice: "npm:^1.0.3" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + data-view-buffer: "npm:^1.0.1" + data-view-byte-length: "npm:^1.0.1" + data-view-byte-offset: "npm:^1.0.0" + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-set-tostringtag: "npm:^2.0.3" + es-to-primitive: "npm:^1.2.1" + function.prototype.name: "npm:^1.1.6" + get-intrinsic: "npm:^1.2.4" + get-symbol-description: "npm:^1.0.2" + globalthis: "npm:^1.0.3" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.0.3" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.2" + internal-slot: "npm:^1.0.7" + is-array-buffer: "npm:^3.0.4" + is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.1" + is-negative-zero: "npm:^2.0.3" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.3" + is-string: "npm:^1.0.7" + is-typed-array: "npm:^1.1.13" + is-weakref: "npm:^1.0.2" + object-inspect: "npm:^1.13.1" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.5" + regexp.prototype.flags: "npm:^1.5.2" + safe-array-concat: "npm:^1.1.2" + safe-regex-test: "npm:^1.0.3" + string.prototype.trim: "npm:^1.2.9" + string.prototype.trimend: "npm:^1.0.8" + string.prototype.trimstart: "npm:^1.0.8" + typed-array-buffer: "npm:^1.0.2" + typed-array-byte-length: "npm:^1.0.1" + typed-array-byte-offset: "npm:^1.0.2" + typed-array-length: "npm:^1.0.6" + unbox-primitive: "npm:^1.0.2" + which-typed-array: "npm:^1.1.15" + checksum: 10/2da795a6a1ac5fc2c452799a409acc2e3692e06dc6440440b076908617188899caa562154d77263e3053bcd9389a07baa978ab10ac3b46acc399bd0c77be04cb + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.0": + version: 1.0.0 + resolution: "es-define-property@npm:1.0.0" + dependencies: + get-intrinsic: "npm:^1.2.4" + checksum: 10/f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 + languageName: node + linkType: hard + +"es-errors@npm:^1.1.0, es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10/96e65d640156f91b707517e8cdc454dd7d47c32833aa3e85d79f24f9eb7ea85f39b63e36216ef0114996581969b59fe609a94e30316b08f5f4df1d44134cf8d5 + languageName: node + linkType: hard + "es-iterator-helpers@npm:^1.0.12": version: 1.0.15 resolution: "es-iterator-helpers@npm:1.0.15" @@ -6132,6 +7964,37 @@ __metadata: languageName: node linkType: hard +"es-iterator-helpers@npm:^1.0.15, es-iterator-helpers@npm:^1.0.17": + version: 1.0.18 + resolution: "es-iterator-helpers@npm:1.0.18" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.0" + es-errors: "npm:^1.3.0" + es-set-tostringtag: "npm:^2.0.3" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + globalthis: "npm:^1.0.3" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.0.3" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.7" + iterator.prototype: "npm:^1.1.2" + safe-array-concat: "npm:^1.1.2" + checksum: 10/a4fd067e148736fbe6a9883f449e0de88be14a4dff9065c457572ede10ba02a4a15c4ae18b9b7baa5c868860d2be9a6764906c3308135e57ec5bfd386bbd2836 + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0": + version: 1.0.0 + resolution: "es-object-atoms@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10/f8910cf477e53c0615f685c5c96210591841850871b81924fcf256bfbaa68c254457d994a4308c60d15b20805e7f61ce6abc669375e01a5349391a8c1767584f + languageName: node + linkType: hard + "es-set-tostringtag@npm:^2.0.1": version: 2.0.2 resolution: "es-set-tostringtag@npm:2.0.2" @@ -6143,7 +8006,18 @@ __metadata: languageName: node linkType: hard -"es-shim-unscopables@npm:^1.0.0": +"es-set-tostringtag@npm:^2.0.3": + version: 2.0.3 + resolution: "es-set-tostringtag@npm:2.0.3" + dependencies: + get-intrinsic: "npm:^1.2.4" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.1" + checksum: 10/7227fa48a41c0ce83e0377b11130d324ac797390688135b8da5c28994c0165be8b252e15cd1de41e1325e5a5412511586960213e88f9ab4a5e7d028895db5129 + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.0, es-shim-unscopables@npm:^1.0.2": version: 1.0.2 resolution: "es-shim-unscopables@npm:1.0.2" dependencies: @@ -6366,6 +8240,67 @@ __metadata: languageName: node linkType: hard +"eslint-config-react-app@npm:^7.0.1": + version: 7.0.1 + resolution: "eslint-config-react-app@npm:7.0.1" + dependencies: + "@babel/core": "npm:^7.16.0" + "@babel/eslint-parser": "npm:^7.16.3" + "@rushstack/eslint-patch": "npm:^1.1.0" + "@typescript-eslint/eslint-plugin": "npm:^5.5.0" + "@typescript-eslint/parser": "npm:^5.5.0" + babel-preset-react-app: "npm:^10.0.1" + confusing-browser-globals: "npm:^1.0.11" + eslint-plugin-flowtype: "npm:^8.0.3" + eslint-plugin-import: "npm:^2.25.3" + eslint-plugin-jest: "npm:^25.3.0" + eslint-plugin-jsx-a11y: "npm:^6.5.1" + eslint-plugin-react: "npm:^7.27.1" + eslint-plugin-react-hooks: "npm:^4.3.0" + eslint-plugin-testing-library: "npm:^5.0.1" + peerDependencies: + eslint: ^8.0.0 + checksum: 10/8bd69354e6ea84eb66712f19b2a11a002bc257d0685f686a985abdc2825499eff5e0bbbc77c0c68b967ad47808904f578bed735c03e28c312f8a469556e8233d + languageName: node + linkType: hard + +"eslint-import-resolver-node@npm:^0.3.9": + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" + dependencies: + debug: "npm:^3.2.7" + is-core-module: "npm:^2.13.0" + resolve: "npm:^1.22.4" + checksum: 10/d52e08e1d96cf630957272e4f2644dcfb531e49dcfd1edd2e07e43369eb2ec7a7d4423d417beee613201206ff2efa4eb9a582b5825ee28802fc7c71fcd53ca83 + languageName: node + linkType: hard + +"eslint-module-utils@npm:^2.8.0": + version: 2.8.1 + resolution: "eslint-module-utils@npm:2.8.1" + dependencies: + debug: "npm:^3.2.7" + peerDependenciesMeta: + eslint: + optional: true + checksum: 10/3e7892c0a984c963632da56b30ccf8254c29b535467138f91086c2ecdb2ebd10e2be61b54e553f30e5abf1d14d47a7baa0dac890e3a658fd3cd07dca63afbe6d + languageName: node + linkType: hard + +"eslint-plugin-flowtype@npm:^8.0.3": + version: 8.0.3 + resolution: "eslint-plugin-flowtype@npm:8.0.3" + dependencies: + lodash: "npm:^4.17.21" + string-natural-compare: "npm:^3.0.1" + peerDependencies: + "@babel/plugin-syntax-flow": ^7.14.5 + "@babel/plugin-transform-react-jsx": ^7.14.9 + eslint: ^8.1.0 + checksum: 10/62a90c57a452cf5a3c510608b3358212b417022a592d367358339d5bbbe07d2b2cb3888745ee211a75e805898c82818fbc990a5f2aff474bbf5bdaaf1618d7c5 + languageName: node + linkType: hard + "eslint-plugin-formatjs@npm:^4.11.3": version: 4.11.3 resolution: "eslint-plugin-formatjs@npm:4.11.3" @@ -6387,7 +8322,77 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.6.0": +"eslint-plugin-import@npm:^2.25.3": + version: 2.29.1 + resolution: "eslint-plugin-import@npm:2.29.1" + dependencies: + array-includes: "npm:^3.1.7" + array.prototype.findlastindex: "npm:^1.2.3" + array.prototype.flat: "npm:^1.3.2" + array.prototype.flatmap: "npm:^1.3.2" + debug: "npm:^3.2.7" + doctrine: "npm:^2.1.0" + eslint-import-resolver-node: "npm:^0.3.9" + eslint-module-utils: "npm:^2.8.0" + hasown: "npm:^2.0.0" + is-core-module: "npm:^2.13.1" + is-glob: "npm:^4.0.3" + minimatch: "npm:^3.1.2" + object.fromentries: "npm:^2.0.7" + object.groupby: "npm:^1.0.1" + object.values: "npm:^1.1.7" + semver: "npm:^6.3.1" + tsconfig-paths: "npm:^3.15.0" + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + checksum: 10/5865f05c38552145423c535326ec9a7113ab2305c7614c8b896ff905cfabc859c8805cac21e979c9f6f742afa333e6f62f812eabf891a7e8f5f0b853a32593c1 + languageName: node + linkType: hard + +"eslint-plugin-jest@npm:^25.3.0": + version: 25.7.0 + resolution: "eslint-plugin-jest@npm:25.7.0" + dependencies: + "@typescript-eslint/experimental-utils": "npm:^5.0.0" + peerDependencies: + "@typescript-eslint/eslint-plugin": ^4.0.0 || ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + "@typescript-eslint/eslint-plugin": + optional: true + jest: + optional: true + checksum: 10/7c358f4503fff7091ddaa8986aba7f4846acc36e7478923cb43fc2cc2ae7be6f49cb1aed222e58d0493154a5e35c4e60111627bf58e72e256831bd2d2c6fd90f + languageName: node + linkType: hard + +"eslint-plugin-jsx-a11y@npm:^6.5.1": + version: 6.8.0 + resolution: "eslint-plugin-jsx-a11y@npm:6.8.0" + dependencies: + "@babel/runtime": "npm:^7.23.2" + aria-query: "npm:^5.3.0" + array-includes: "npm:^3.1.7" + array.prototype.flatmap: "npm:^1.3.2" + ast-types-flow: "npm:^0.0.8" + axe-core: "npm:=4.7.0" + axobject-query: "npm:^3.2.1" + damerau-levenshtein: "npm:^1.0.8" + emoji-regex: "npm:^9.2.2" + es-iterator-helpers: "npm:^1.0.15" + hasown: "npm:^2.0.0" + jsx-ast-utils: "npm:^3.3.5" + language-tags: "npm:^1.0.9" + minimatch: "npm:^3.1.2" + object.entries: "npm:^1.1.7" + object.fromentries: "npm:^2.0.7" + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + checksum: 10/7a8e4498531a43d988ce2f12502a3f5ce96eacfec13f956cf927f24bb041b724fb7fc0f0306ea19d143bfc79e138bf25e25acca0822847206ac6bf5ce095e846 + languageName: node + linkType: hard + +"eslint-plugin-react-hooks@npm:^4.3.0, eslint-plugin-react-hooks@npm:^4.6.0": version: 4.6.0 resolution: "eslint-plugin-react-hooks@npm:4.6.0" peerDependencies: @@ -6405,6 +8410,34 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-react@npm:^7.27.1": + version: 7.34.1 + resolution: "eslint-plugin-react@npm:7.34.1" + dependencies: + array-includes: "npm:^3.1.7" + array.prototype.findlast: "npm:^1.2.4" + array.prototype.flatmap: "npm:^1.3.2" + array.prototype.toreversed: "npm:^1.1.2" + array.prototype.tosorted: "npm:^1.1.3" + doctrine: "npm:^2.1.0" + es-iterator-helpers: "npm:^1.0.17" + estraverse: "npm:^5.3.0" + jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" + minimatch: "npm:^3.1.2" + object.entries: "npm:^1.1.7" + object.fromentries: "npm:^2.0.7" + object.hasown: "npm:^1.1.3" + object.values: "npm:^1.1.7" + prop-types: "npm:^15.8.1" + resolve: "npm:^2.0.0-next.5" + semver: "npm:^6.3.1" + string.prototype.matchall: "npm:^4.0.10" + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + checksum: 10/ee059971065ea7e73ab5d8728774235c7dbf7a5e9f937c3b47e97f8fa9a5a96ab511d2ae6d5ec76a7e705ca666673d454f1e75a94033720819d041827f50f9c8 + languageName: node + linkType: hard + "eslint-plugin-react@npm:^7.33.2": version: 7.33.2 resolution: "eslint-plugin-react@npm:7.33.2" @@ -6440,6 +8473,27 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-testing-library@npm:^5.0.1": + version: 5.11.1 + resolution: "eslint-plugin-testing-library@npm:5.11.1" + dependencies: + "@typescript-eslint/utils": "npm:^5.58.0" + peerDependencies: + eslint: ^7.5.0 || ^8.0.0 + checksum: 10/3b2f010b13fbffd9a2018815cdca7edfce64523d9263ed376b33bdc43fca297100dab755a40f5b8be0f8e76b44bc7883590acfa9016fbff20888d9ee67f964d0 + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10/c541ef384c92eb5c999b7d3443d80195fcafb3da335500946f6db76539b87d5826c8f2e1d23bf6afc3154ba8cd7c8e566f8dc00f1eea25fdf3afc8fb9c87b238 + languageName: node + linkType: hard + "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -6450,6 +8504,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^2.1.0": + version: 2.1.0 + resolution: "eslint-visitor-keys@npm:2.1.0" + checksum: 10/db4547eef5039122d518fa307e938ceb8589da5f6e8f5222efaf14dd62f748ce82e2d2becd3ff9412a50350b726bda95dbea8515a471074547daefa58aee8735 + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" @@ -6544,6 +8605,13 @@ __metadata: languageName: node linkType: hard +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10/3f67ad02b6dbfaddd9ea459cf2b6ef4ecff9a6082a7af9d22e445b9abc082ad9ca47e1825557b293fcdae477f4714e561123e30bb6a5b2f184fb2bad4a9497eb + languageName: node + linkType: hard + "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" @@ -6558,6 +8626,13 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^2.0.1": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10/b02109c5d46bc2ed47de4990eef770f7457b1159a229f0999a09224d2b85ffeed2d7679cffcff90aeb4448e94b0168feb5265b209cdec29aad50a3d6e93d21e2 + languageName: node + linkType: hard + "estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -6929,6 +9004,19 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10/85bbf4b234c3940edf8a41f4ecbd4e25ce78e5e6ad4e24ca2f77037d983b9ef943fd72f00f3ee97a49ec622a506b67db49c36246150377efcda1c9eb03e5f06d + languageName: node + linkType: hard + "get-own-enumerable-property-symbols@npm:^3.0.0": version: 3.0.2 resolution: "get-own-enumerable-property-symbols@npm:3.0.2" @@ -6960,6 +9048,17 @@ __metadata: languageName: node linkType: hard +"get-symbol-description@npm:^1.0.2": + version: 1.0.2 + resolution: "get-symbol-description@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.5" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + checksum: 10/e1cb53bc211f9dbe9691a4f97a46837a553c4e7caadd0488dc24ac694db8a390b93edd412b48dcdd0b4bbb4c595de1709effc75fc87c0839deedc6968f5bd973 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -7113,6 +9212,15 @@ __metadata: languageName: node linkType: hard +"has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: "npm:^1.0.0" + checksum: 10/2d8c9ab8cebb572e3362f7d06139a4592105983d4317e68f7adba320fe6ddfc8874581e0971e899e633fd5f72e262830edce36d5a0bc863dad17ad20572484b2 + languageName: node + linkType: hard + "has-proto@npm:^1.0.1": version: 1.0.1 resolution: "has-proto@npm:1.0.1" @@ -7120,6 +9228,13 @@ __metadata: languageName: node linkType: hard +"has-proto@npm:^1.0.3": + version: 1.0.3 + resolution: "has-proto@npm:1.0.3" + checksum: 10/0b67c2c94e3bea37db3e412e3c41f79d59259875e636ba471e94c009cdfb1fa82bf045deeffafc7dbb9c148e36cae6b467055aaa5d9fad4316e11b41e3ba551a + languageName: node + linkType: hard + "has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": version: 1.0.3 resolution: "has-symbols@npm:1.0.3" @@ -7136,6 +9251,15 @@ __metadata: languageName: node linkType: hard +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: "npm:^1.0.3" + checksum: 10/c74c5f5ceee3c8a5b8bc37719840dc3749f5b0306d818974141dda2471a1a2ca6c8e46b9d6ac222c5345df7a901c9b6f350b1e6d62763fec877e26609a401bfe + languageName: node + linkType: hard + "hasown@npm:^2.0.0": version: 2.0.0 resolution: "hasown@npm:2.0.0" @@ -7145,6 +9269,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.1, hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10/7898a9c1788b2862cf0f9c345a6bec77ba4a0c0983c7f19d610c382343d4f98fa260686b225dfb1f88393a66679d2ec58ee310c1d6868c081eda7918f32cc70a + languageName: node + linkType: hard + "highlight.js@npm:^11.8.0": version: 11.9.0 resolution: "highlight.js@npm:11.9.0" @@ -7333,6 +9466,17 @@ __metadata: languageName: node linkType: hard +"internal-slot@npm:^1.0.7": + version: 1.0.7 + resolution: "internal-slot@npm:1.0.7" + dependencies: + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.0" + side-channel: "npm:^1.0.4" + checksum: 10/3e66720508831153ecf37d13def9f6856f9f2960989ec8a0a0476c98f887fca9eff0163127466485cb825c900c2d6fc601aa9117b7783b90ffce23a71ea5d053 + languageName: node + linkType: hard + "internmap@npm:1 - 2": version: 2.0.3 resolution: "internmap@npm:2.0.3" @@ -7370,6 +9514,16 @@ __metadata: languageName: node linkType: hard +"is-array-buffer@npm:^3.0.4": + version: 3.0.4 + resolution: "is-array-buffer@npm:3.0.4" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.1" + checksum: 10/34a26213d981d58b30724ef37a1e0682f4040d580fa9ff58fdfdd3cefcb2287921718c63971c1c404951e7b747c50fdc7caf6e867e951353fa71b369c04c969b + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -7421,7 +9575,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.13.0": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1": version: 2.13.1 resolution: "is-core-module@npm:2.13.1" dependencies: @@ -7430,6 +9584,15 @@ __metadata: languageName: node linkType: hard +"is-data-view@npm:^1.0.1": + version: 1.0.1 + resolution: "is-data-view@npm:1.0.1" + dependencies: + is-typed-array: "npm:^1.1.13" + checksum: 10/4ba4562ac2b2ec005fefe48269d6bd0152785458cd253c746154ffb8a8ab506a29d0cfb3b74af87513843776a88e4981ae25c89457bf640a33748eab1a7216b5 + languageName: node + linkType: hard + "is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" @@ -7524,6 +9687,13 @@ __metadata: languageName: node linkType: hard +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5 + languageName: node + linkType: hard + "is-number-object@npm:^1.0.4": version: 1.0.7 resolution: "is-number-object@npm:1.0.7" @@ -7603,6 +9773,15 @@ __metadata: languageName: node linkType: hard +"is-shared-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "is-shared-array-buffer@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.7" + checksum: 10/bc5402900dc62b96ebb2548bf5b0a0bcfacc2db122236fe3ab3b3e3c884293a0d5eb777e73f059bcbf8dc8563bb65eae972fee0fb97e38a9ae27c8678f62bcfe + languageName: node + linkType: hard + "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" @@ -7637,6 +9816,15 @@ __metadata: languageName: node linkType: hard +"is-typed-array@npm:^1.1.13": + version: 1.1.13 + resolution: "is-typed-array@npm:1.1.13" + dependencies: + which-typed-array: "npm:^1.1.14" + checksum: 10/f850ba08286358b9a11aee6d93d371a45e3c59b5953549ee1c1a9a55ba5c1dd1bd9952488ae194ad8f32a9cf5e79c8fa5f0cc4d78c00720aa0bbcf238b38062d + languageName: node + linkType: hard + "is-weakmap@npm:^2.0.1": version: 2.0.1 resolution: "is-weakmap@npm:2.0.1" @@ -8435,6 +10623,17 @@ __metadata: languageName: node linkType: hard +"json5@npm:^1.0.2": + version: 1.0.2 + resolution: "json5@npm:1.0.2" + dependencies: + minimist: "npm:^1.2.0" + bin: + json5: lib/cli.js + checksum: 10/a78d812dbbd5642c4f637dd130954acfd231b074965871c3e28a5bbd571f099d623ecf9161f1960c4ddf68e0cc98dee8bebfdb94a71ad4551f85a1afc94b63f6 + languageName: node + linkType: hard + "json5@npm:^2.2.0, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -8478,7 +10677,7 @@ __metadata: languageName: node linkType: hard -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0": +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": version: 3.3.5 resolution: "jsx-ast-utils@npm:3.3.5" dependencies: @@ -8515,6 +10714,22 @@ __metadata: languageName: node linkType: hard +"language-subtag-registry@npm:^0.3.20": + version: 0.3.22 + resolution: "language-subtag-registry@npm:0.3.22" + checksum: 10/5591f4abd775d1ab5945355a5ba894327d2d94c900607bdb69aac1bc5bb921dbeeeb5f616df95e8c0ae875501d19c1cfa0e852ece822121e95048deb34f2b4d2 + languageName: node + linkType: hard + +"language-tags@npm:^1.0.9": + version: 1.0.9 + resolution: "language-tags@npm:1.0.9" + dependencies: + language-subtag-registry: "npm:^0.3.20" + checksum: 10/d3a7c14b694e67f519153d6df6cb200681648d38d623c3bfa9d6a66a5ec5493628acb88e9df5aceef3cf1902ab263a205e7d59ee4cf1d6bb67e707b83538bd6d + languageName: node + linkType: hard + "latlon-geohash@npm:^2.0.0": version: 2.0.0 resolution: "latlon-geohash@npm:2.0.0" @@ -8921,6 +11136,13 @@ __metadata: languageName: node linkType: hard +"minimist@npm:^1.2.0, minimist@npm:^1.2.6": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f + languageName: node + linkType: hard + "minipass-collect@npm:^1.0.2": version: 1.0.2 resolution: "minipass-collect@npm:1.0.2" @@ -9040,6 +11262,13 @@ __metadata: languageName: node linkType: hard +"ms@npm:^2.1.1": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + "mz@npm:^2.7.0": version: 2.7.0 resolution: "mz@npm:2.7.0" @@ -9060,6 +11289,13 @@ __metadata: languageName: node linkType: hard +"natural-compare-lite@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare-lite@npm:1.4.0" + checksum: 10/5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 + languageName: node + linkType: hard + "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -9149,6 +11385,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 10/0f7607ec7db5ef1dc616899a5f24ae90c869b6a54c2d4f36ff6d84a282ab9343c7ff3ca3670fe4669171bb1e8a9b3e286e1ef1c131f09a83d70554f855d54f24 + languageName: node + linkType: hard + "nopt@npm:^7.0.0": version: 7.2.0 resolution: "nopt@npm:7.2.0" @@ -9267,6 +11510,18 @@ __metadata: languageName: node linkType: hard +"object.assign@npm:^4.1.5": + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" + dependencies: + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + has-symbols: "npm:^1.0.3" + object-keys: "npm:^1.1.1" + checksum: 10/dbb22da4cda82e1658349ea62b80815f587b47131b3dd7a4ab7f84190ab31d206bbd8fe7e26ae3220c55b65725ac4529825f6142154211220302aa6b1518045d + languageName: node + linkType: hard + "object.entries@npm:^1.1.6": version: 1.1.7 resolution: "object.entries@npm:1.1.7" @@ -9278,6 +11533,17 @@ __metadata: languageName: node linkType: hard +"object.entries@npm:^1.1.7": + version: 1.1.8 + resolution: "object.entries@npm:1.1.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/2301918fbd1ee697cf6ff7cd94f060c738c0a7d92b22fd24c7c250e9b593642c9707ad2c44d339303c1439c5967d8964251cdfc855f7f6ec55db2dd79e8dc2a7 + languageName: node + linkType: hard + "object.fromentries@npm:^2.0.6": version: 2.0.7 resolution: "object.fromentries@npm:2.0.7" @@ -9289,6 +11555,29 @@ __metadata: languageName: node linkType: hard +"object.fromentries@npm:^2.0.7": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10/5b2e80f7af1778b885e3d06aeb335dcc86965e39464671adb7167ab06ac3b0f5dd2e637a90d8ebd7426d69c6f135a4753ba3dd7d0fe2a7030cf718dcb910fd92 + languageName: node + linkType: hard + +"object.groupby@npm:^1.0.1": + version: 1.0.3 + resolution: "object.groupby@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + checksum: 10/44cb86dd2c660434be65f7585c54b62f0425b0c96b5c948d2756be253ef06737da7e68d7106e35506ce4a44d16aa85a413d11c5034eb7ce5579ec28752eb42d0 + languageName: node + linkType: hard + "object.hasown@npm:^1.1.2": version: 1.1.3 resolution: "object.hasown@npm:1.1.3" @@ -9299,6 +11588,17 @@ __metadata: languageName: node linkType: hard +"object.hasown@npm:^1.1.3": + version: 1.1.4 + resolution: "object.hasown@npm:1.1.4" + dependencies: + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10/797385577b3ef3c0d19333e03ed34bc7987978ae1ee1245069c9922e17d1128265187f729dc610260d03f8d418af26fcd7919b423793bf0af9099d9f08367d69 + languageName: node + linkType: hard + "object.values@npm:^1.1.6": version: 1.1.7 resolution: "object.values@npm:1.1.7" @@ -9310,6 +11610,17 @@ __metadata: languageName: node linkType: hard +"object.values@npm:^1.1.7": + version: 1.2.0 + resolution: "object.values@npm:1.2.0" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/db2e498019c354428c5dd30d02980d920ac365b155fce4dcf63eb9433f98ccf0f72624309e182ce7cc227c95e45d474e1d483418e60de2293dd23fa3ebe34903 + languageName: node + linkType: hard + "once@npm:^1.3.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -9423,7 +11734,7 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.2.0": +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -9571,6 +11882,13 @@ __metadata: languageName: node linkType: hard +"possible-typed-array-names@npm:^1.0.0": + version: 1.0.0 + resolution: "possible-typed-array-names@npm:1.0.0" + checksum: 10/8ed3e96dfeea1c5880c1f4c9cb707e5fb26e8be22f14f82ef92df20fd2004e635c62ba47fbe8f2bb63bfd80dac1474be2fb39798da8c2feba2815435d1f749af + languageName: node + linkType: hard + "postcss-attribute-case-insensitive@npm:^6.0.2": version: 6.0.2 resolution: "postcss-attribute-case-insensitive@npm:6.0.2" @@ -10487,6 +12805,18 @@ __metadata: languageName: node linkType: hard +"regexp.prototype.flags@npm:^1.5.2": + version: 1.5.2 + resolution: "regexp.prototype.flags@npm:1.5.2" + dependencies: + call-bind: "npm:^1.0.6" + define-properties: "npm:^1.2.1" + es-errors: "npm:^1.3.0" + set-function-name: "npm:^2.0.1" + checksum: 10/9fffc01da9c4e12670ff95bc5204364615fcc12d86fc30642765af908675678ebb0780883c874b2dbd184505fb52fa603d80073ecf69f461ce7f56b15d10be9c + languageName: node + linkType: hard + "regexpu-core@npm:^5.3.1": version: 5.3.2 resolution: "regexpu-core@npm:5.3.2" @@ -10570,7 +12900,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2": +"resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -10583,7 +12913,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^2.0.0-next.4": +"resolve@npm:^2.0.0-next.4, resolve@npm:^2.0.0-next.5": version: 2.0.0-next.5 resolution: "resolve@npm:2.0.0-next.5" dependencies: @@ -10596,7 +12926,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -10609,7 +12939,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^2.0.0-next.4#optional!builtin": +"resolve@patch:resolve@npm%3A^2.0.0-next.4#optional!builtin, resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": version: 2.0.0-next.5 resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" dependencies: @@ -10680,7 +13010,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.43.1": +"rollup@npm:^2.43.1, rollup@npm:^2.77.2": version: 2.79.1 resolution: "rollup@npm:2.79.1" dependencies: @@ -10838,6 +13168,18 @@ __metadata: languageName: node linkType: hard +"safe-array-concat@npm:^1.1.2": + version: 1.1.2 + resolution: "safe-array-concat@npm:1.1.2" + dependencies: + call-bind: "npm:^1.0.7" + get-intrinsic: "npm:^1.2.4" + has-symbols: "npm:^1.0.3" + isarray: "npm:^2.0.5" + checksum: 10/a54f8040d7cb696a1ee38d19cc71ab3cfb654b9b81bae00c6459618cfad8214ece7e6666592f9c925aafef43d0a20c5e6fbb3413a2b618e1ce9d516a2e6dcfc5 + languageName: node + linkType: hard + "safe-buffer@npm:^5.1.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" @@ -10856,6 +13198,17 @@ __metadata: languageName: node linkType: hard +"safe-regex-test@npm:^1.0.3": + version: 1.0.3 + resolution: "safe-regex-test@npm:1.0.3" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-regex: "npm:^1.1.4" + checksum: 10/b04de61114b10274d92e25b6de7ccb5de07f11ea15637ff636de4b5190c0f5cd8823fe586dde718504cf78055437d70fd8804976894df502fcf5a210c970afb3 + languageName: node + linkType: hard + "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -10901,6 +13254,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.3.7": + version: 7.6.0 + resolution: "semver@npm:7.6.0" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 10/1b41018df2d8aca5a1db4729985e8e20428c650daea60fcd16e926e9383217d00f574fab92d79612771884a98d2ee2a1973f49d630829a8d54d6570defe62535 + languageName: node + linkType: hard + "serialize-javascript@npm:^4.0.0": version: 4.0.0 resolution: "serialize-javascript@npm:4.0.0" @@ -10922,6 +13286,20 @@ __metadata: languageName: node linkType: hard +"set-function-length@npm:^1.2.1": + version: 1.2.2 + resolution: "set-function-length@npm:1.2.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + checksum: 10/505d62b8e088468917ca4e3f8f39d0e29f9a563b97dbebf92f4bd2c3172ccfb3c5b8e4566d5fcd00784a00433900e7cb8fbc404e2dbd8c3818ba05bb9d4a8a6d + languageName: node + linkType: hard + "set-function-name@npm:^2.0.0, set-function-name@npm:^2.0.1": version: 2.0.1 resolution: "set-function-name@npm:2.0.1" @@ -10933,6 +13311,18 @@ __metadata: languageName: node linkType: hard +"set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + checksum: 10/c7614154a53ebf8c0428a6c40a3b0b47dac30587c1a19703d1b75f003803f73cdfa6a93474a9ba678fa565ef5fbddc2fae79bca03b7d22ab5fd5163dbe571a74 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -10972,6 +13362,18 @@ __metadata: languageName: node linkType: hard +"side-channel@npm:^1.0.6": + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + object-inspect: "npm:^1.13.1" + checksum: 10/eb10944f38cebad8ad643dd02657592fa41273ce15b8bfa928d3291aff2d30c20ff777cfe908f76ccc4551ace2d1245822fdc576657cce40e9066c638ca8fa4d + languageName: node + linkType: hard + "siginfo@npm:^2.0.0": version: 2.0.0 resolution: "siginfo@npm:2.0.0" @@ -11189,6 +13591,13 @@ __metadata: languageName: node linkType: hard +"string-natural-compare@npm:^3.0.1": + version: 3.0.1 + resolution: "string-natural-compare@npm:3.0.1" + checksum: 10/bc1fd0ee196466489e121bbe11844094ddcdee5a687dca9dbb18ba2ace73b1f6c96c9b448df2dfed0879b781b6b12e329ca1c1fc0a86d70b00c7823b76109b1e + languageName: node + linkType: hard + "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -11211,6 +13620,26 @@ __metadata: languageName: node linkType: hard +"string.prototype.matchall@npm:^4.0.10": + version: 4.0.11 + resolution: "string.prototype.matchall@npm:4.0.11" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.7" + regexp.prototype.flags: "npm:^1.5.2" + set-function-name: "npm:^2.0.2" + side-channel: "npm:^1.0.6" + checksum: 10/a902ff4500f909f2a08e55cc5ab1ffbbc905f603b36837674370ee3921058edd0392147e15891910db62a2f31ace2adaf065eaa3bc6e9810bdbc8ca48e05a7b5 + languageName: node + linkType: hard + "string.prototype.matchall@npm:^4.0.6, string.prototype.matchall@npm:^4.0.8": version: 4.0.10 resolution: "string.prototype.matchall@npm:4.0.10" @@ -11239,6 +13668,18 @@ __metadata: languageName: node linkType: hard +"string.prototype.trim@npm:^1.2.9": + version: 1.2.9 + resolution: "string.prototype.trim@npm:1.2.9" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.0" + es-object-atoms: "npm:^1.0.0" + checksum: 10/b2170903de6a2fb5a49bb8850052144e04b67329d49f1343cdc6a87cb24fb4e4b8ad00d3e273a399b8a3d8c32c89775d93a8f43cb42fbff303f25382079fb58a + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.7": version: 1.0.7 resolution: "string.prototype.trimend@npm:1.0.7" @@ -11250,6 +13691,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimend@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimend@npm:1.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/c2e862ae724f95771da9ea17c27559d4eeced9208b9c20f69bbfcd1b9bc92375adf8af63a103194dba17c4cc4a5cb08842d929f415ff9d89c062d44689c8761b + languageName: node + linkType: hard + "string.prototype.trimstart@npm:^1.0.7": version: 1.0.7 resolution: "string.prototype.trimstart@npm:1.0.7" @@ -11261,6 +13713,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimstart@npm:1.0.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/160167dfbd68e6f7cb9f51a16074eebfce1571656fc31d40c3738ca9e30e35496f2c046fe57b6ad49f65f238a152be8c86fd9a2dd58682b5eba39dad995b3674 + languageName: node + linkType: hard + "stringify-object@npm:^3.3.0": version: 3.3.0 resolution: "stringify-object@npm:3.3.0" @@ -11290,6 +13753,13 @@ __metadata: languageName: node linkType: hard +"strip-bom@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-bom@npm:3.0.0" + checksum: 10/8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b + languageName: node + linkType: hard + "strip-bom@npm:^4.0.0": version: 4.0.0 resolution: "strip-bom@npm:4.0.0" @@ -11753,6 +14223,18 @@ __metadata: languageName: node linkType: hard +"tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" + dependencies: + "@types/json5": "npm:^0.0.29" + json5: "npm:^1.0.2" + minimist: "npm:^1.2.6" + strip-bom: "npm:^3.0.0" + checksum: 10/2041beaedc6c271fc3bedd12e0da0cc553e65d030d4ff26044b771fac5752d0460944c0b5e680f670c2868c95c664a256cec960ae528888db6ded83524e33a14 + languageName: node + linkType: hard + "tslib@npm:2.6.2, tslib@npm:^2.0.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1, tslib@npm:^2.6.2": version: 2.6.2 resolution: "tslib@npm:2.6.2" @@ -11760,6 +14242,24 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^1.8.1": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb + languageName: node + linkType: hard + +"tsutils@npm:^3.21.0": + version: 3.21.0 + resolution: "tsutils@npm:3.21.0" + dependencies: + tslib: "npm:^1.8.1" + peerDependencies: + typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + checksum: 10/ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2 + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -11808,6 +14308,17 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-buffer@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.13" + checksum: 10/02ffc185d29c6df07968272b15d5319a1610817916ec8d4cd670ded5d1efe72901541ff2202fcc622730d8a549c76e198a2f74e312eabbfb712ed907d45cbb0b + languageName: node + linkType: hard + "typed-array-byte-length@npm:^1.0.0": version: 1.0.0 resolution: "typed-array-byte-length@npm:1.0.0" @@ -11820,6 +14331,19 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "typed-array-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + checksum: 10/e4a38329736fe6a73b52a09222d4a9e8de14caaa4ff6ad8e55217f6705b017d9815b7284c85065b3b8a7704e226ccff1372a72b78c2a5b6b71b7bf662308c903 + languageName: node + linkType: hard + "typed-array-byte-offset@npm:^1.0.0": version: 1.0.0 resolution: "typed-array-byte-offset@npm:1.0.0" @@ -11833,6 +14357,20 @@ __metadata: languageName: node linkType: hard +"typed-array-byte-offset@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-byte-offset@npm:1.0.2" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + checksum: 10/ac26d720ebb2aacbc45e231347c359e6649f52e0cfe0e76e62005912f8030d68e4cb7b725b1754e8fdd48e433cb68df5a8620a3e420ad1457d666e8b29bf9150 + languageName: node + linkType: hard + "typed-array-length@npm:^1.0.4": version: 1.0.4 resolution: "typed-array-length@npm:1.0.4" @@ -11844,6 +14382,20 @@ __metadata: languageName: node linkType: hard +"typed-array-length@npm:^1.0.6": + version: 1.0.6 + resolution: "typed-array-length@npm:1.0.6" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + possible-typed-array-names: "npm:^1.0.0" + checksum: 10/05e96cf4ff836743ebfc593d86133b8c30e83172cb5d16c56814d7bacfed57ce97e87ada9c4b2156d9aaa59f75cdef01c25bd9081c7826e0b869afbefc3e8c39 + languageName: node + linkType: hard + "typedoc@npm:^0.25.7": version: 0.25.7 resolution: "typedoc@npm:0.25.7" @@ -12186,6 +14738,20 @@ __metadata: languageName: node linkType: hard +"vite-plugin-eslint@npm:^1.8.1": + version: 1.8.1 + resolution: "vite-plugin-eslint@npm:1.8.1" + dependencies: + "@rollup/pluginutils": "npm:^4.2.1" + "@types/eslint": "npm:^8.4.5" + rollup: "npm:^2.77.2" + peerDependencies: + eslint: ">=7" + vite: ">=2" + checksum: 10/65598893e2063a287a690ae296ba1fc212ee50dbc810d396a6cda44ee60c6f400adb52fc4c4a5ff54a89c11100bbaaf43eada23c9a78654ab1717f097d78176f + languageName: node + linkType: hard + "vite-plugin-pwa@npm:^0.19.2": version: 0.19.2 resolution: "vite-plugin-pwa@npm:0.19.2" @@ -12508,6 +15074,19 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15": + version: 1.1.15 + resolution: "which-typed-array@npm:1.1.15" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.2" + checksum: 10/c3b6a99beadc971baa53c3ee5b749f2b9bdfa3b3b9a70650dd8511a48b61d877288b498d424712e9991d16019633086bd8b5923369460d93463c5825fa36c448 + languageName: node + linkType: hard + "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -12861,6 +15440,13 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^1.10.0": + version: 1.10.2 + resolution: "yaml@npm:1.10.2" + checksum: 10/e088b37b4d4885b70b50c9fa1b7e54bd2e27f5c87205f9deaffd1fb293ab263d9c964feadb9817a7b129a5bf30a06582cb08750f810568ecc14f3cdbabb79cb3 + languageName: node + linkType: hard + "yaml@npm:^2.1.1": version: 2.3.4 resolution: "yaml@npm:2.3.4"