From 81ccb95d828c39597dd6f6b277cf6882a4adbbcb Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 8 Jun 2023 12:45:23 +0200 Subject: [PATCH] move to pkg --- packages/app/.gitignore | 2 + packages/app/src/Cache/DMCache.ts | 2 +- packages/app/src/Cache/UserCache.ts | 2 +- packages/app/src/Cache/index.ts | 49 --- packages/app/src/Const.ts | 4 +- packages/app/src/Db/index.ts | 3 +- packages/app/src/Element/Avatar.tsx | 2 +- packages/app/src/Element/BadgeList.tsx | 2 +- packages/app/src/Element/BlockButton.tsx | 2 +- packages/app/src/Element/Bookmarks.tsx | 2 +- packages/app/src/Element/DM.tsx | 2 +- packages/app/src/Element/DmWindow.tsx | 2 +- packages/app/src/Element/FollowButton.tsx | 2 +- packages/app/src/Element/FollowListBase.tsx | 2 +- packages/app/src/Element/Mention.tsx | 2 +- packages/app/src/Element/MuteButton.tsx | 2 +- packages/app/src/Element/MutedList.tsx | 2 +- packages/app/src/Element/Nip05.tsx | 2 +- packages/app/src/Element/Nip5Service.tsx | 4 +- packages/app/src/Element/NostrFileHeader.tsx | 4 +- packages/app/src/Element/NostrLink.tsx | 3 +- packages/app/src/Element/Note.tsx | 3 +- packages/app/src/Element/NoteCreator.tsx | 3 +- packages/app/src/Element/NoteFooter.tsx | 2 +- packages/app/src/Element/NoteQuote.tsx | 2 +- packages/app/src/Element/NoteReaction.tsx | 3 +- packages/app/src/Element/Poll.tsx | 2 +- packages/app/src/Element/ProfileImage.tsx | 3 +- packages/app/src/Element/ProfilePreview.tsx | 2 +- packages/app/src/Element/PubkeyList.tsx | 2 +- packages/app/src/Element/Reactions.tsx | 2 +- packages/app/src/Element/Relay.tsx | 2 +- packages/app/src/Element/RelaysMetadata.tsx | 2 +- packages/app/src/Element/SendSats.tsx | 3 +- packages/app/src/Element/SubDebug.tsx | 2 +- .../app/src/Element/SuggestedProfiles.tsx | 2 +- packages/app/src/Element/Text.tsx | 4 +- packages/app/src/Element/Textarea.tsx | 3 +- packages/app/src/Element/Thread.tsx | 13 +- packages/app/src/Element/Timeline.tsx | 2 +- packages/app/src/Element/TrendingPosts.tsx | 2 +- packages/app/src/Element/TrendingUsers.tsx | 2 +- packages/app/src/Element/Username.tsx | 2 +- packages/app/src/Element/WriteDm.tsx | 2 +- packages/app/src/Element/Zap.tsx | 2 +- packages/app/src/Element/ZapButton.tsx | 2 +- packages/app/src/Element/ZapstrEmbed.tsx | 2 +- packages/app/src/External/NostrBand.ts | 2 +- packages/app/src/Feed/BadgesFeed.ts | 4 +- packages/app/src/Feed/BookmarkFeed.tsx | 2 +- packages/app/src/Feed/EventFeed.ts | 5 +- packages/app/src/Feed/EventPublisher.ts | 2 +- packages/app/src/Feed/FollowersFeed.ts | 3 +- packages/app/src/Feed/FollowsFeed.ts | 3 +- packages/app/src/Feed/LoginFeed.ts | 3 +- packages/app/src/Feed/MuteList.ts | 10 +- packages/app/src/Feed/PinnedFeed.tsx | 2 +- packages/app/src/Feed/RelaysFeed.tsx | 4 +- packages/app/src/Feed/RelaysFeedFollows.tsx | 11 +- packages/app/src/Feed/ThreadFeed.ts | 5 +- packages/app/src/Feed/TimelineFeed.ts | 3 +- packages/app/src/Feed/ZapsFeed.ts | 3 +- .../app/src/Hooks/useInteractionCache.tsx | 2 +- packages/app/src/Hooks/useModeration.tsx | 2 +- .../app/src/Hooks/useNotelistSubscription.ts | 10 +- packages/app/src/Hooks/useRequestBuilder.tsx | 3 +- packages/app/src/Hooks/useSystemState.tsx | 2 +- packages/app/src/Hooks/useUserProfile.ts | 3 +- packages/app/src/LNURL.ts | 2 +- packages/app/src/Login/Functions.ts | 3 +- packages/app/src/Login/LoginSession.ts | 2 +- packages/app/src/Login/MultiAccountStore.ts | 2 +- .../app/src/Nip05/SnortServiceProvider.ts | 3 +- packages/app/src/Notifications.ts | 3 +- packages/app/src/Pages/DonatePage.tsx | 2 +- packages/app/src/Pages/LoginPage.tsx | 2 +- packages/app/src/Pages/MessagesPage.tsx | 2 +- packages/app/src/Pages/NostrLinkHandler.tsx | 4 +- packages/app/src/Pages/ProfilePage.tsx | 4 +- packages/app/src/Pages/new/ProfileSetup.tsx | 3 +- packages/app/src/Pages/settings/Keys.tsx | 2 +- packages/app/src/Pages/settings/Profile.tsx | 3 +- packages/app/src/Pages/settings/Relays.tsx | 1 - packages/app/src/SnortApi.ts | 3 +- packages/app/src/SnortUtils/Utils.test.ts | 47 +-- packages/app/src/SnortUtils/index.ts | 114 +----- packages/app/src/State/NoteCreator.ts | 2 +- packages/app/src/State/ReBroadcast.ts | 2 +- packages/app/src/System/Const.ts | 4 - packages/app/src/System/Util.test.ts | 72 ---- packages/app/src/Tasks/Nip5Task.tsx | 2 +- packages/app/src/Tasks/index.ts | 2 +- packages/app/src/Upload/VoidCat.ts | 3 +- packages/app/src/Upload/index.ts | 2 +- packages/app/src/Wallet/NostrWalletConnect.ts | 4 +- packages/app/src/index.tsx | 7 +- packages/system/.npmignore | 5 + packages/system/dist/Connection.d.ts | 90 +++++ packages/system/dist/Connection.d.ts.map | 1 + packages/system/dist/Connection.js | 343 ++++++++++++++++++ packages/system/dist/Connection.js.map | 1 + packages/system/dist/ConnectionStats.d.ts | 30 ++ packages/system/dist/ConnectionStats.d.ts.map | 1 + packages/system/dist/ConnectionStats.js | 36 ++ packages/system/dist/ConnectionStats.js.map | 1 + packages/system/dist/Const.d.ts | 13 + packages/system/dist/Const.d.ts.map | 1 + packages/system/dist/Const.js | 17 + packages/system/dist/Const.js.map | 1 + packages/system/dist/EventBuilder.d.ts | 20 + packages/system/dist/EventBuilder.d.ts.map | 1 + packages/system/dist/EventBuilder.js | 113 ++++++ packages/system/dist/EventBuilder.js.map | 1 + packages/system/dist/EventExt.d.ts | 42 +++ packages/system/dist/EventExt.d.ts.map | 1 + packages/system/dist/EventExt.js | 175 +++++++++ packages/system/dist/EventExt.js.map | 1 + packages/system/dist/EventKind.d.ts | 29 ++ packages/system/dist/EventKind.d.ts.map | 1 + packages/system/dist/EventKind.js | 32 ++ packages/system/dist/EventKind.js.map | 1 + packages/system/dist/EventPublisher.d.ts | 66 ++++ packages/system/dist/EventPublisher.d.ts.map | 1 + packages/system/dist/EventPublisher.js | 295 +++++++++++++++ packages/system/dist/EventPublisher.js.map | 1 + packages/system/dist/ExternalStore.d.ts | 13 + packages/system/dist/ExternalStore.d.ts.map | 1 + packages/system/dist/ExternalStore.js | 49 +++ packages/system/dist/ExternalStore.js.map | 1 + packages/system/dist/GossipModel.d.ts | 20 + packages/system/dist/GossipModel.d.ts.map | 1 + packages/system/dist/GossipModel.js | 102 ++++++ packages/system/dist/GossipModel.js.map | 1 + packages/system/dist/Links.d.ts | 24 ++ packages/system/dist/Links.d.ts.map | 1 + packages/system/dist/Links.js | 102 ++++++ packages/system/dist/Links.js.map | 1 + packages/system/dist/Nips.d.ts | 4 + packages/system/dist/Nips.d.ts.map | 1 + packages/system/dist/Nips.js | 8 + packages/system/dist/Nips.js.map | 1 + packages/system/dist/Nostr.d.ts | 75 ++++ packages/system/dist/Nostr.d.ts.map | 1 + packages/system/dist/Nostr.js | 15 + packages/system/dist/Nostr.js.map | 1 + packages/system/dist/NostrLink.d.ts | 13 + packages/system/dist/NostrLink.d.ts.map | 1 + packages/system/dist/NostrLink.js | 110 ++++++ packages/system/dist/NostrLink.js.map | 1 + packages/system/dist/NostrSystem.d.ts | 75 ++++ packages/system/dist/NostrSystem.d.ts.map | 1 + packages/system/dist/NostrSystem.js | 237 ++++++++++++ packages/system/dist/NostrSystem.js.map | 1 + packages/system/dist/NoteCollection.d.ts | 91 +++++ packages/system/dist/NoteCollection.d.ts.map | 1 + packages/system/dist/NoteCollection.js | 240 ++++++++++++ packages/system/dist/NoteCollection.js.map | 1 + packages/system/dist/ProfileCache.d.ts | 20 + packages/system/dist/ProfileCache.d.ts.map | 1 + packages/system/dist/ProfileCache.js | 129 +++++++ packages/system/dist/ProfileCache.js.map | 1 + packages/system/dist/Query.d.ts | 86 +++++ packages/system/dist/Query.d.ts.map | 1 + packages/system/dist/Query.js | 228 ++++++++++++ packages/system/dist/Query.js.map | 1 + packages/system/dist/RelayInfo.d.ts | 17 + packages/system/dist/RelayInfo.d.ts.map | 1 + packages/system/dist/RelayInfo.js | 3 + packages/system/dist/RelayInfo.js.map | 1 + packages/system/dist/RequestBuilder.d.ts | 93 +++++ packages/system/dist/RequestBuilder.d.ts.map | 1 + packages/system/dist/RequestBuilder.js | 225 ++++++++++++ packages/system/dist/RequestBuilder.js.map | 1 + packages/system/dist/RequestExpander.d.ts | 20 + packages/system/dist/RequestExpander.d.ts.map | 1 + packages/system/dist/RequestExpander.js | 31 ++ packages/system/dist/RequestExpander.js.map | 1 + packages/system/dist/RequestMatcher.d.ts | 3 + packages/system/dist/RequestMatcher.d.ts.map | 1 + packages/system/dist/RequestMatcher.js | 23 ++ packages/system/dist/RequestMatcher.js.map | 1 + packages/system/dist/RequestMerger.d.ts | 24 ++ packages/system/dist/RequestMerger.d.ts.map | 1 + packages/system/dist/RequestMerger.js | 150 ++++++++ packages/system/dist/RequestMerger.js.map | 1 + packages/system/dist/RequestSplitter.d.ts | 7 + packages/system/dist/RequestSplitter.d.ts.map | 1 + packages/system/dist/RequestSplitter.js | 19 + packages/system/dist/RequestSplitter.js.map | 1 + packages/system/dist/SystemWorker.d.ts | 22 ++ packages/system/dist/SystemWorker.d.ts.map | 1 + packages/system/dist/SystemWorker.js | 66 ++++ packages/system/dist/SystemWorker.js.map | 1 + packages/system/dist/Tag.d.ts | 18 + packages/system/dist/Tag.d.ts.map | 1 + packages/system/dist/Tag.js | 75 ++++ packages/system/dist/Tag.js.map | 1 + packages/system/dist/Util.d.ts | 23 ++ packages/system/dist/Util.d.ts.map | 1 + packages/system/dist/Util.js | 148 ++++++++ packages/system/dist/Util.js.map | 1 + packages/system/dist/WorkQueue.d.ts | 8 + packages/system/dist/WorkQueue.d.ts.map | 1 + packages/system/dist/WorkQueue.js | 30 ++ packages/system/dist/WorkQueue.js.map | 1 + packages/system/dist/cache/index.d.ts | 48 +++ packages/system/dist/cache/index.d.ts.map | 1 + packages/system/dist/cache/index.js | 21 ++ packages/system/dist/cache/index.js.map | 1 + packages/system/dist/index.d.ts | 44 +++ packages/system/dist/index.d.ts.map | 1 + packages/system/dist/index.js | 39 ++ packages/system/dist/index.js.map | 1 + packages/system/jest.config.js | 9 + packages/system/package.json | 29 ++ packages/system/snort-system-1.0.0.tgz | Bin 0 -> 56011 bytes .../src/System => system/src}/Connection.ts | 2 +- .../System => system/src}/ConnectionStats.ts | 0 packages/system/src/Const.ts | 16 + .../src/System => system/src}/EventBuilder.ts | 7 +- .../src/System => system/src}/EventExt.ts | 15 +- .../src/System => system/src}/EventKind.ts | 0 .../System => system/src}/EventPublisher.ts | 18 +- packages/system/src/ExternalStore.ts | 41 +++ .../src/System => system/src}/GossipModel.ts | 4 +- .../{app/src/System => system/src}/Links.ts | 0 .../{app/src/System => system/src}/Nips.ts | 0 .../{app/src/System => system/src}/Nostr.ts | 0 packages/system/src/NostrLink.ts | 110 ++++++ .../src/System => system/src}/NostrSystem.ts | 11 +- .../System => system/src}/NoteCollection.ts | 4 +- .../src/System => system/src}/ProfileCache.ts | 24 +- .../{app/src/System => system/src}/Query.ts | 7 +- .../src/System => system/src}/RelayInfo.ts | 0 .../System => system/src}/RequestBuilder.ts | 4 +- .../System => system/src}/RequestExpander.ts | 0 .../System => system/src}/RequestMatcher.ts | 0 .../System => system/src}/RequestMerger.ts | 2 +- .../System => system/src}/RequestSplitter.ts | 2 +- .../src/System => system/src}/SystemWorker.ts | 19 +- .../{app/src/System => system/src}/Tag.ts | 0 .../{app/src/System => system/src}/Util.ts | 36 ++ packages/system/src/WorkQueue.ts | 30 ++ packages/system/src/cache/index.ts | 68 ++++ .../{app/src/System => system/src}/index.ts | 39 +- .../tests}/NoteCollection.test.ts | 4 +- .../src/System => system/tests}/Query.test.ts | 8 +- .../tests}/RequestBuilder.test.ts | 4 +- .../tests}/RequestExpander.test.ts | 2 +- .../tests}/RequestMatcher.test.ts | 2 +- .../tests}/RequestMerger.test.ts | 8 +- .../tests}/RequestSplitter.test.ts | 4 +- packages/system/tests/Util.test.ts | 117 ++++++ packages/system/tests/setupTests.ts | 3 + packages/system/tsconfig.json | 18 + packages/{app/src/System => system}/worker.ts | 2 +- 256 files changed, 4856 insertions(+), 529 deletions(-) delete mode 100644 packages/app/src/System/Const.ts delete mode 100644 packages/app/src/System/Util.test.ts create mode 100644 packages/system/.npmignore create mode 100644 packages/system/dist/Connection.d.ts create mode 100644 packages/system/dist/Connection.d.ts.map create mode 100644 packages/system/dist/Connection.js create mode 100644 packages/system/dist/Connection.js.map create mode 100644 packages/system/dist/ConnectionStats.d.ts create mode 100644 packages/system/dist/ConnectionStats.d.ts.map create mode 100644 packages/system/dist/ConnectionStats.js create mode 100644 packages/system/dist/ConnectionStats.js.map create mode 100644 packages/system/dist/Const.d.ts create mode 100644 packages/system/dist/Const.d.ts.map create mode 100644 packages/system/dist/Const.js create mode 100644 packages/system/dist/Const.js.map create mode 100644 packages/system/dist/EventBuilder.d.ts create mode 100644 packages/system/dist/EventBuilder.d.ts.map create mode 100644 packages/system/dist/EventBuilder.js create mode 100644 packages/system/dist/EventBuilder.js.map create mode 100644 packages/system/dist/EventExt.d.ts create mode 100644 packages/system/dist/EventExt.d.ts.map create mode 100644 packages/system/dist/EventExt.js create mode 100644 packages/system/dist/EventExt.js.map create mode 100644 packages/system/dist/EventKind.d.ts create mode 100644 packages/system/dist/EventKind.d.ts.map create mode 100644 packages/system/dist/EventKind.js create mode 100644 packages/system/dist/EventKind.js.map create mode 100644 packages/system/dist/EventPublisher.d.ts create mode 100644 packages/system/dist/EventPublisher.d.ts.map create mode 100644 packages/system/dist/EventPublisher.js create mode 100644 packages/system/dist/EventPublisher.js.map create mode 100644 packages/system/dist/ExternalStore.d.ts create mode 100644 packages/system/dist/ExternalStore.d.ts.map create mode 100644 packages/system/dist/ExternalStore.js create mode 100644 packages/system/dist/ExternalStore.js.map create mode 100644 packages/system/dist/GossipModel.d.ts create mode 100644 packages/system/dist/GossipModel.d.ts.map create mode 100644 packages/system/dist/GossipModel.js create mode 100644 packages/system/dist/GossipModel.js.map create mode 100644 packages/system/dist/Links.d.ts create mode 100644 packages/system/dist/Links.d.ts.map create mode 100644 packages/system/dist/Links.js create mode 100644 packages/system/dist/Links.js.map create mode 100644 packages/system/dist/Nips.d.ts create mode 100644 packages/system/dist/Nips.d.ts.map create mode 100644 packages/system/dist/Nips.js create mode 100644 packages/system/dist/Nips.js.map create mode 100644 packages/system/dist/Nostr.d.ts create mode 100644 packages/system/dist/Nostr.d.ts.map create mode 100644 packages/system/dist/Nostr.js create mode 100644 packages/system/dist/Nostr.js.map create mode 100644 packages/system/dist/NostrLink.d.ts create mode 100644 packages/system/dist/NostrLink.d.ts.map create mode 100644 packages/system/dist/NostrLink.js create mode 100644 packages/system/dist/NostrLink.js.map create mode 100644 packages/system/dist/NostrSystem.d.ts create mode 100644 packages/system/dist/NostrSystem.d.ts.map create mode 100644 packages/system/dist/NostrSystem.js create mode 100644 packages/system/dist/NostrSystem.js.map create mode 100644 packages/system/dist/NoteCollection.d.ts create mode 100644 packages/system/dist/NoteCollection.d.ts.map create mode 100644 packages/system/dist/NoteCollection.js create mode 100644 packages/system/dist/NoteCollection.js.map create mode 100644 packages/system/dist/ProfileCache.d.ts create mode 100644 packages/system/dist/ProfileCache.d.ts.map create mode 100644 packages/system/dist/ProfileCache.js create mode 100644 packages/system/dist/ProfileCache.js.map create mode 100644 packages/system/dist/Query.d.ts create mode 100644 packages/system/dist/Query.d.ts.map create mode 100644 packages/system/dist/Query.js create mode 100644 packages/system/dist/Query.js.map create mode 100644 packages/system/dist/RelayInfo.d.ts create mode 100644 packages/system/dist/RelayInfo.d.ts.map create mode 100644 packages/system/dist/RelayInfo.js create mode 100644 packages/system/dist/RelayInfo.js.map create mode 100644 packages/system/dist/RequestBuilder.d.ts create mode 100644 packages/system/dist/RequestBuilder.d.ts.map create mode 100644 packages/system/dist/RequestBuilder.js create mode 100644 packages/system/dist/RequestBuilder.js.map create mode 100644 packages/system/dist/RequestExpander.d.ts create mode 100644 packages/system/dist/RequestExpander.d.ts.map create mode 100644 packages/system/dist/RequestExpander.js create mode 100644 packages/system/dist/RequestExpander.js.map create mode 100644 packages/system/dist/RequestMatcher.d.ts create mode 100644 packages/system/dist/RequestMatcher.d.ts.map create mode 100644 packages/system/dist/RequestMatcher.js create mode 100644 packages/system/dist/RequestMatcher.js.map create mode 100644 packages/system/dist/RequestMerger.d.ts create mode 100644 packages/system/dist/RequestMerger.d.ts.map create mode 100644 packages/system/dist/RequestMerger.js create mode 100644 packages/system/dist/RequestMerger.js.map create mode 100644 packages/system/dist/RequestSplitter.d.ts create mode 100644 packages/system/dist/RequestSplitter.d.ts.map create mode 100644 packages/system/dist/RequestSplitter.js create mode 100644 packages/system/dist/RequestSplitter.js.map create mode 100644 packages/system/dist/SystemWorker.d.ts create mode 100644 packages/system/dist/SystemWorker.d.ts.map create mode 100644 packages/system/dist/SystemWorker.js create mode 100644 packages/system/dist/SystemWorker.js.map create mode 100644 packages/system/dist/Tag.d.ts create mode 100644 packages/system/dist/Tag.d.ts.map create mode 100644 packages/system/dist/Tag.js create mode 100644 packages/system/dist/Tag.js.map create mode 100644 packages/system/dist/Util.d.ts create mode 100644 packages/system/dist/Util.d.ts.map create mode 100644 packages/system/dist/Util.js create mode 100644 packages/system/dist/Util.js.map create mode 100644 packages/system/dist/WorkQueue.d.ts create mode 100644 packages/system/dist/WorkQueue.d.ts.map create mode 100644 packages/system/dist/WorkQueue.js create mode 100644 packages/system/dist/WorkQueue.js.map create mode 100644 packages/system/dist/cache/index.d.ts create mode 100644 packages/system/dist/cache/index.d.ts.map create mode 100644 packages/system/dist/cache/index.js create mode 100644 packages/system/dist/cache/index.js.map create mode 100644 packages/system/dist/index.d.ts create mode 100644 packages/system/dist/index.d.ts.map create mode 100644 packages/system/dist/index.js create mode 100644 packages/system/dist/index.js.map create mode 100644 packages/system/jest.config.js create mode 100644 packages/system/package.json create mode 100644 packages/system/snort-system-1.0.0.tgz rename packages/{app/src/System => system/src}/Connection.ts (99%) rename packages/{app/src/System => system/src}/ConnectionStats.ts (100%) create mode 100644 packages/system/src/Const.ts rename packages/{app/src/System => system/src}/EventBuilder.ts (91%) rename packages/{app/src/System => system/src}/EventExt.ts (92%) rename packages/{app/src/System => system/src}/EventKind.ts (100%) rename packages/{app/src/System => system/src}/EventPublisher.ts (93%) create mode 100644 packages/system/src/ExternalStore.ts rename packages/{app/src/System => system/src}/GossipModel.ts (96%) rename packages/{app/src/System => system/src}/Links.ts (100%) rename packages/{app/src/System => system/src}/Nips.ts (100%) rename packages/{app/src/System => system/src}/Nostr.ts (100%) create mode 100644 packages/system/src/NostrLink.ts rename packages/{app/src/System => system/src}/NostrSystem.ts (95%) rename packages/{app/src/System => system/src}/NoteCollection.ts (98%) rename packages/{app/src/System => system/src}/ProfileCache.ts (83%) rename packages/{app/src/System => system/src}/Query.ts (96%) rename packages/{app/src/System => system/src}/RelayInfo.ts (100%) rename packages/{app/src/System => system/src}/RequestBuilder.ts (98%) rename packages/{app/src/System => system/src}/RequestExpander.ts (100%) rename packages/{app/src/System => system/src}/RequestMatcher.ts (100%) rename packages/{app/src/System => system/src}/RequestMerger.ts (99%) rename packages/{app/src/System => system/src}/RequestSplitter.ts (94%) rename packages/{app/src/System => system/src}/SystemWorker.ts (80%) rename packages/{app/src/System => system/src}/Tag.ts (100%) rename packages/{app/src/System => system/src}/Util.ts (68%) create mode 100644 packages/system/src/WorkQueue.ts create mode 100644 packages/system/src/cache/index.ts rename packages/{app/src/System => system/src}/index.ts (58%) rename packages/{app/src/System => system/tests}/NoteCollection.test.ts (93%) rename packages/{app/src/System => system/tests}/Query.test.ts (92%) rename packages/{app/src/System => system/tests}/RequestBuilder.test.ts (97%) rename packages/{app/src/System => system/tests}/RequestExpander.test.ts (96%) rename packages/{app/src/System => system/tests}/RequestMatcher.test.ts (88%) rename packages/{app/src/System => system/tests}/RequestMerger.test.ts (93%) rename packages/{app/src/System => system/tests}/RequestSplitter.test.ts (96%) create mode 100644 packages/system/tests/Util.test.ts create mode 100644 packages/system/tests/setupTests.ts create mode 100644 packages/system/tsconfig.json rename packages/{app/src/System => system}/worker.ts (88%) diff --git a/packages/app/.gitignore b/packages/app/.gitignore index 3a1bea68..3486a8a6 100644 --- a/packages/app/.gitignore +++ b/packages/app/.gitignore @@ -23,3 +23,5 @@ yarn-debug.log* yarn-error.log* .idea + +dist/ diff --git a/packages/app/src/Cache/DMCache.ts b/packages/app/src/Cache/DMCache.ts index 7cbce8df..4041a0fc 100644 --- a/packages/app/src/Cache/DMCache.ts +++ b/packages/app/src/Cache/DMCache.ts @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import { db } from "Db"; import FeedCache from "./FeedCache"; diff --git a/packages/app/src/Cache/UserCache.ts b/packages/app/src/Cache/UserCache.ts index 731a7422..1b9ce04b 100644 --- a/packages/app/src/Cache/UserCache.ts +++ b/packages/app/src/Cache/UserCache.ts @@ -1,6 +1,6 @@ import FeedCache from "Cache/FeedCache"; import { db } from "Db"; -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; import { LNURL } from "LNURL"; import { fetchNip05Pubkey } from "Nip05/Verifier"; diff --git a/packages/app/src/Cache/index.ts b/packages/app/src/Cache/index.ts index 0f0cabb4..ec3f6c0f 100644 --- a/packages/app/src/Cache/index.ts +++ b/packages/app/src/Cache/index.ts @@ -1,57 +1,8 @@ -import { HexKey, NostrEvent, UserMetadata } from "System"; -import { hexToBech32, unixNowMs } from "SnortUtils"; import { DmCache } from "./DMCache"; import { InteractionCache } from "./EventInteractionCache"; import { UserCache } from "./UserCache"; import { UserRelays } from "./UserRelayCache"; -export interface MetadataCache extends UserMetadata { - /** - * When the object was saved in cache - */ - loaded: number; - - /** - * When the source metadata event was created - */ - created: number; - - /** - * The pubkey of the owner of this metadata - */ - pubkey: HexKey; - - /** - * The bech32 encoded pubkey - */ - npub: string; - - /** - * Pubkey of zapper service - */ - zapService?: HexKey; - - /** - * If the nip05 is valid for this user - */ - isNostrAddressValid: boolean; -} - -export function mapEventToProfile(ev: NostrEvent) { - try { - const data: UserMetadata = JSON.parse(ev.content); - return { - ...data, - pubkey: ev.pubkey, - npub: hexToBech32("npub", ev.pubkey), - created: ev.created_at, - loaded: unixNowMs(), - } as MetadataCache; - } catch (e) { - console.error("Failed to parse JSON", ev, e); - } -} - export async function preload(follows?: Array) { const preloads = [ UserCache.preload(follows), diff --git a/packages/app/src/Const.ts b/packages/app/src/Const.ts index e16d2262..db961bc6 100644 --- a/packages/app/src/Const.ts +++ b/packages/app/src/Const.ts @@ -1,6 +1,4 @@ -import { UserRelays } from "Cache/UserRelayCache"; -import { NostrSystem, RelaySettings } from "System"; -import { ProfileLoaderService } from "System/ProfileCache"; +import { RelaySettings } from "@snort/system"; /** * Add-on api for snort features diff --git a/packages/app/src/Db/index.ts b/packages/app/src/Db/index.ts index 9a72e8f3..cb501536 100644 --- a/packages/app/src/Db/index.ts +++ b/packages/app/src/Db/index.ts @@ -1,6 +1,5 @@ import Dexie, { Table } from "dexie"; -import { FullRelaySettings, HexKey, NostrEvent, u256 } from "System"; -import { MetadataCache } from "Cache"; +import { FullRelaySettings, HexKey, NostrEvent, u256, MetadataCache } from "@snort/system"; export const NAME = "snortDB"; export const VERSION = 8; diff --git a/packages/app/src/Element/Avatar.tsx b/packages/app/src/Element/Avatar.tsx index 576ef169..89fef4aa 100644 --- a/packages/app/src/Element/Avatar.tsx +++ b/packages/app/src/Element/Avatar.tsx @@ -2,7 +2,7 @@ import "./Avatar.css"; import Nostrich from "nostrich.webp"; import { CSSProperties, useEffect, useState } from "react"; -import type { UserMetadata } from "System"; +import type { UserMetadata } from "@snort/system"; import useImgProxy from "Hooks/useImgProxy"; diff --git a/packages/app/src/Element/BadgeList.tsx b/packages/app/src/Element/BadgeList.tsx index e007b685..36088902 100644 --- a/packages/app/src/Element/BadgeList.tsx +++ b/packages/app/src/Element/BadgeList.tsx @@ -3,7 +3,7 @@ import "./BadgeList.css"; import { useState } from "react"; import { FormattedMessage } from "react-intl"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { ProxyImg } from "Element/ProxyImg"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Element/BlockButton.tsx b/packages/app/src/Element/BlockButton.tsx index 10c4859f..3245d76d 100644 --- a/packages/app/src/Element/BlockButton.tsx +++ b/packages/app/src/Element/BlockButton.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useModeration from "Hooks/useModeration"; import messages from "./messages"; diff --git a/packages/app/src/Element/Bookmarks.tsx b/packages/app/src/Element/Bookmarks.tsx index 04680f64..118cf917 100644 --- a/packages/app/src/Element/Bookmarks.tsx +++ b/packages/app/src/Element/Bookmarks.tsx @@ -1,6 +1,6 @@ import { useState, useMemo, ChangeEvent } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey, TaggedRawEvent } from "System"; +import { HexKey, TaggedRawEvent } from "@snort/system"; import Note from "Element/Note"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Element/DM.tsx b/packages/app/src/Element/DM.tsx index de058fee..2a8e9efa 100644 --- a/packages/app/src/Element/DM.tsx +++ b/packages/app/src/Element/DM.tsx @@ -2,7 +2,7 @@ import "./DM.css"; import { useEffect, useState } from "react"; import { useIntl } from "react-intl"; import { useInView } from "react-intersection-observer"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import NoteTime from "Element/NoteTime"; diff --git a/packages/app/src/Element/DmWindow.tsx b/packages/app/src/Element/DmWindow.tsx index 827984b7..b56e95c0 100644 --- a/packages/app/src/Element/DmWindow.tsx +++ b/packages/app/src/Element/DmWindow.tsx @@ -1,6 +1,6 @@ import "./DmWindow.css"; import { useEffect, useMemo, useRef } from "react"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import ProfileImage from "Element/ProfileImage"; import DM from "Element/DM"; diff --git a/packages/app/src/Element/FollowButton.tsx b/packages/app/src/Element/FollowButton.tsx index e284bc83..72e3fb33 100644 --- a/packages/app/src/Element/FollowButton.tsx +++ b/packages/app/src/Element/FollowButton.tsx @@ -1,6 +1,6 @@ import "./FollowButton.css"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import { parseId } from "SnortUtils"; diff --git a/packages/app/src/Element/FollowListBase.tsx b/packages/app/src/Element/FollowListBase.tsx index e98ef131..fc0b09dc 100644 --- a/packages/app/src/Element/FollowListBase.tsx +++ b/packages/app/src/Element/FollowListBase.tsx @@ -1,6 +1,6 @@ import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import ProfilePreview from "Element/ProfilePreview"; diff --git a/packages/app/src/Element/Mention.tsx b/packages/app/src/Element/Mention.tsx index b7a8af60..9fe4723e 100644 --- a/packages/app/src/Element/Mention.tsx +++ b/packages/app/src/Element/Mention.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react"; import { Link } from "react-router-dom"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { profileLink } from "SnortUtils"; diff --git a/packages/app/src/Element/MuteButton.tsx b/packages/app/src/Element/MuteButton.tsx index 7f8d492f..b95d1e21 100644 --- a/packages/app/src/Element/MuteButton.tsx +++ b/packages/app/src/Element/MuteButton.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useModeration from "Hooks/useModeration"; import messages from "./messages"; diff --git a/packages/app/src/Element/MutedList.tsx b/packages/app/src/Element/MutedList.tsx index 6fa9044c..b3ecb946 100644 --- a/packages/app/src/Element/MutedList.tsx +++ b/packages/app/src/Element/MutedList.tsx @@ -1,5 +1,5 @@ import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import MuteButton from "Element/MuteButton"; import ProfilePreview from "Element/ProfilePreview"; import useModeration from "Hooks/useModeration"; diff --git a/packages/app/src/Element/Nip05.tsx b/packages/app/src/Element/Nip05.tsx index e3e14170..5e1de7ab 100644 --- a/packages/app/src/Element/Nip05.tsx +++ b/packages/app/src/Element/Nip05.tsx @@ -1,5 +1,5 @@ import "./Nip05.css"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import Icon from "Icons/Icon"; import { useUserProfile } from "Hooks/useUserProfile"; diff --git a/packages/app/src/Element/Nip5Service.tsx b/packages/app/src/Element/Nip5Service.tsx index 122c249b..3eb16982 100644 --- a/packages/app/src/Element/Nip5Service.tsx +++ b/packages/app/src/Element/Nip5Service.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState, ChangeEvent } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { UserMetadata } from "System"; +import { UserMetadata, mapEventToProfile } from "@snort/system"; import { unwrap } from "SnortUtils"; import { formatShort } from "Number"; @@ -22,7 +22,7 @@ import useEventPublisher from "Feed/EventPublisher"; import { debounce } from "SnortUtils"; import useLogin from "Hooks/useLogin"; import SnortServiceProvider from "Nip05/SnortServiceProvider"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import messages from "./messages"; diff --git a/packages/app/src/Element/NostrFileHeader.tsx b/packages/app/src/Element/NostrFileHeader.tsx index 512d09df..b4efdc0d 100644 --- a/packages/app/src/Element/NostrFileHeader.tsx +++ b/packages/app/src/Element/NostrFileHeader.tsx @@ -1,7 +1,7 @@ import { FormattedMessage } from "react-intl"; -import { NostrEvent } from "System"; +import { NostrEvent, NostrLink } from "@snort/system"; -import { findTag, NostrLink } from "SnortUtils"; +import { findTag } from "SnortUtils"; import useEventFeed from "Feed/EventFeed"; import PageSpinner from "Element/PageSpinner"; import Reveal from "Element/Reveal"; diff --git a/packages/app/src/Element/NostrLink.tsx b/packages/app/src/Element/NostrLink.tsx index 64efbde8..28ea734a 100644 --- a/packages/app/src/Element/NostrLink.tsx +++ b/packages/app/src/Element/NostrLink.tsx @@ -1,8 +1,7 @@ import { Link } from "react-router-dom"; -import { NostrPrefix } from "System"; +import { NostrPrefix, parseNostrLink } from "@snort/system"; import Mention from "Element/Mention"; -import { parseNostrLink } from "SnortUtils"; import NoteQuote from "Element/NoteQuote"; export default function NostrLink({ link, depth }: { link: string; depth?: number }) { diff --git a/packages/app/src/Element/Note.tsx b/packages/app/src/Element/Note.tsx index 5a582f6a..10115754 100644 --- a/packages/app/src/Element/Note.tsx +++ b/packages/app/src/Element/Note.tsx @@ -3,7 +3,7 @@ import React, { useMemo, useState, useLayoutEffect, ReactNode } from "react"; import { useNavigate, Link } from "react-router-dom"; import { useInView } from "react-intersection-observer"; import { useIntl, FormattedMessage } from "react-intl"; -import { TaggedRawEvent, HexKey, EventKind, NostrPrefix, Lists } from "System"; +import { TaggedRawEvent, HexKey, EventKind, NostrPrefix, Lists, EventExt } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import Icon from "Icons/Icon"; @@ -26,7 +26,6 @@ import Reveal from "Element/Reveal"; import useModeration from "Hooks/useModeration"; import { UserCache } from "Cache/UserCache"; import Poll from "Element/Poll"; -import { EventExt } from "System/EventExt"; import useLogin from "Hooks/useLogin"; import { setBookmarked, setPinned } from "Login"; import { NostrFileElement } from "Element/NostrFileHeader"; diff --git a/packages/app/src/Element/NoteCreator.tsx b/packages/app/src/Element/NoteCreator.tsx index 6a4a2a4a..958cc179 100644 --- a/packages/app/src/Element/NoteCreator.tsx +++ b/packages/app/src/Element/NoteCreator.tsx @@ -1,7 +1,7 @@ import "./NoteCreator.css"; import { FormattedMessage, useIntl } from "react-intl"; import { useDispatch, useSelector } from "react-redux"; -import { encodeTLV, EventKind, NostrPrefix, TaggedRawEvent } from "System"; +import { encodeTLV, EventKind, NostrPrefix, TaggedRawEvent, EventBuilder } from "@snort/system"; import Icon from "Icons/Icon"; import useEventPublisher from "Feed/EventPublisher"; @@ -31,7 +31,6 @@ import { LNURL } from "LNURL"; import messages from "./messages"; import { ClipboardEventHandler, useState } from "react"; import Spinner from "Icons/Spinner"; -import { EventBuilder } from "System"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { LoginStore } from "Login"; import { getCurrentSubscription } from "Subscription"; diff --git a/packages/app/src/Element/NoteFooter.tsx b/packages/app/src/Element/NoteFooter.tsx index 25fef378..800c4d31 100644 --- a/packages/app/src/Element/NoteFooter.tsx +++ b/packages/app/src/Element/NoteFooter.tsx @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from "react-redux"; import { useIntl, FormattedMessage } from "react-intl"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { useLongPress } from "use-long-press"; -import { TaggedRawEvent, HexKey, u256, encodeTLV, NostrPrefix, Lists } from "System"; +import { TaggedRawEvent, HexKey, u256, encodeTLV, NostrPrefix, Lists } from "@snort/system"; import Icon from "Icons/Icon"; import Spinner from "Icons/Spinner"; diff --git a/packages/app/src/Element/NoteQuote.tsx b/packages/app/src/Element/NoteQuote.tsx index 31cca7ba..262b1ca6 100644 --- a/packages/app/src/Element/NoteQuote.tsx +++ b/packages/app/src/Element/NoteQuote.tsx @@ -1,5 +1,5 @@ import useEventFeed from "Feed/EventFeed"; -import { NostrLink } from "SnortUtils"; +import { NostrLink } from "@snort/system"; import Note from "Element/Note"; import PageSpinner from "Element/PageSpinner"; diff --git a/packages/app/src/Element/NoteReaction.tsx b/packages/app/src/Element/NoteReaction.tsx index 1849c904..00301dac 100644 --- a/packages/app/src/Element/NoteReaction.tsx +++ b/packages/app/src/Element/NoteReaction.tsx @@ -1,14 +1,13 @@ import "./NoteReaction.css"; import { Link } from "react-router-dom"; import { useMemo } from "react"; -import { EventKind, NostrEvent, TaggedRawEvent, NostrPrefix } from "System"; +import { EventKind, NostrEvent, TaggedRawEvent, NostrPrefix, EventExt } from "@snort/system"; import Note from "Element/Note"; import ProfileImage from "Element/ProfileImage"; import { eventLink, hexToBech32 } from "SnortUtils"; import NoteTime from "Element/NoteTime"; import useModeration from "Hooks/useModeration"; -import { EventExt } from "System/EventExt"; export interface NoteReactionProps { data: TaggedRawEvent; diff --git a/packages/app/src/Element/Poll.tsx b/packages/app/src/Element/Poll.tsx index bb29730e..4ef7dcf9 100644 --- a/packages/app/src/Element/Poll.tsx +++ b/packages/app/src/Element/Poll.tsx @@ -1,4 +1,4 @@ -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { useState } from "react"; import { FormattedMessage, FormattedNumber, useIntl } from "react-intl"; diff --git a/packages/app/src/Element/ProfileImage.tsx b/packages/app/src/Element/ProfileImage.tsx index 96c5e15a..5745b9c7 100644 --- a/packages/app/src/Element/ProfileImage.tsx +++ b/packages/app/src/Element/ProfileImage.tsx @@ -1,13 +1,12 @@ import "./ProfileImage.css"; import React, { useMemo } from "react"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix, MetadataCache } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { hexToBech32, profileLink } from "SnortUtils"; import Avatar from "Element/Avatar"; import Nip05 from "Element/Nip05"; -import { MetadataCache } from "Cache"; import { Link } from "react-router-dom"; export interface ProfileImageProps { diff --git a/packages/app/src/Element/ProfilePreview.tsx b/packages/app/src/Element/ProfilePreview.tsx index 15f02c05..6397e778 100644 --- a/packages/app/src/Element/ProfilePreview.tsx +++ b/packages/app/src/Element/ProfilePreview.tsx @@ -4,7 +4,7 @@ import { ReactNode } from "react"; import ProfileImage from "Element/ProfileImage"; import FollowButton from "Element/FollowButton"; import { useUserProfile } from "Hooks/useUserProfile"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useInView } from "react-intersection-observer"; export interface ProfilePreviewProps { diff --git a/packages/app/src/Element/PubkeyList.tsx b/packages/app/src/Element/PubkeyList.tsx index 6350af3f..5812e6fa 100644 --- a/packages/app/src/Element/PubkeyList.tsx +++ b/packages/app/src/Element/PubkeyList.tsx @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import { dedupe } from "SnortUtils"; import FollowListBase from "./FollowListBase"; diff --git a/packages/app/src/Element/Reactions.tsx b/packages/app/src/Element/Reactions.tsx index 2dcfbe30..8e723277 100644 --- a/packages/app/src/Element/Reactions.tsx +++ b/packages/app/src/Element/Reactions.tsx @@ -2,7 +2,7 @@ import "./Reactions.css"; import { useState, useMemo, useEffect } from "react"; import { useIntl, FormattedMessage } from "react-intl"; -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "@snort/system"; import { formatShort } from "Number"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Element/Relay.tsx b/packages/app/src/Element/Relay.tsx index e79ed1ab..ab3d3de9 100644 --- a/packages/app/src/Element/Relay.tsx +++ b/packages/app/src/Element/Relay.tsx @@ -2,7 +2,7 @@ import "./Relay.css"; import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { RelaySettings } from "System"; +import { RelaySettings } from "@snort/system"; import useRelayState from "Feed/RelayState"; import { System } from "index"; diff --git a/packages/app/src/Element/RelaysMetadata.tsx b/packages/app/src/Element/RelaysMetadata.tsx index 8973a428..5df1631e 100644 --- a/packages/app/src/Element/RelaysMetadata.tsx +++ b/packages/app/src/Element/RelaysMetadata.tsx @@ -2,7 +2,7 @@ import "./RelaysMetadata.css"; import Nostrich from "nostrich.webp"; import { useState } from "react"; -import { FullRelaySettings } from "System"; +import { FullRelaySettings } from "@snort/system"; import Icon from "Icons/Icon"; const RelayFavicon = ({ url }: { url: string }) => { diff --git a/packages/app/src/Element/SendSats.tsx b/packages/app/src/Element/SendSats.tsx index 765c5929..1c55269d 100644 --- a/packages/app/src/Element/SendSats.tsx +++ b/packages/app/src/Element/SendSats.tsx @@ -2,7 +2,7 @@ import "./SendSats.css"; import React, { useEffect, useMemo, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; -import { HexKey, NostrEvent } from "System"; +import { HexKey, NostrEvent, EventPublisher } from "@snort/system"; import { System } from "index"; import { formatShort } from "Number"; import Icon from "Icons/Icon"; @@ -16,7 +16,6 @@ import { chunks, debounce } from "SnortUtils"; import { useWallet } from "Wallet"; import useLogin from "Hooks/useLogin"; import { generateRandomKey } from "Login"; -import { EventPublisher } from "System/EventPublisher"; import { ZapPoolController } from "ZapPoolController"; import messages from "./messages"; diff --git a/packages/app/src/Element/SubDebug.tsx b/packages/app/src/Element/SubDebug.tsx index 73375741..bf1707fe 100644 --- a/packages/app/src/Element/SubDebug.tsx +++ b/packages/app/src/Element/SubDebug.tsx @@ -5,7 +5,7 @@ import useRelayState from "Feed/RelayState"; import Tabs, { Tab } from "Element/Tabs"; import { unwrap } from "SnortUtils"; import useSystemState from "Hooks/useSystemState"; -import { ReqFilter } from "System"; +import { ReqFilter } from "@snort/system"; import { useCopy } from "useCopy"; import { System } from "index"; diff --git a/packages/app/src/Element/SuggestedProfiles.tsx b/packages/app/src/Element/SuggestedProfiles.tsx index 5cb06808..7d86420c 100644 --- a/packages/app/src/Element/SuggestedProfiles.tsx +++ b/packages/app/src/Element/SuggestedProfiles.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix } from "@snort/system"; import { FormattedMessage } from "react-intl"; import FollowListBase from "Element/FollowListBase"; diff --git a/packages/app/src/Element/Text.tsx b/packages/app/src/Element/Text.tsx index 89ede775..779c35b8 100644 --- a/packages/app/src/Element/Text.tsx +++ b/packages/app/src/Element/Text.tsx @@ -1,10 +1,10 @@ import "./Text.css"; import { useMemo } from "react"; import { Link, useLocation } from "react-router-dom"; -import { HexKey, NostrPrefix } from "System"; +import { HexKey, NostrPrefix, validateNostrLink } from "@snort/system"; import { MentionRegex, InvoiceRegex, HashtagRegex, CashuRegex } from "Const"; -import { eventLink, hexToBech32, splitByUrl, validateNostrLink } from "SnortUtils"; +import { eventLink, hexToBech32, splitByUrl } from "SnortUtils"; import Invoice from "Element/Invoice"; import Hashtag from "Element/Hashtag"; import Mention from "Element/Mention"; diff --git a/packages/app/src/Element/Textarea.tsx b/packages/app/src/Element/Textarea.tsx index c92c497e..352ade10 100644 --- a/packages/app/src/Element/Textarea.tsx +++ b/packages/app/src/Element/Textarea.tsx @@ -4,12 +4,11 @@ import "./Textarea.css"; import { useIntl } from "react-intl"; import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete"; import TextareaAutosize from "react-textarea-autosize"; -import { NostrPrefix } from "System"; +import { NostrPrefix, MetadataCache } from "@snort/system"; import Avatar from "Element/Avatar"; import Nip05 from "Element/Nip05"; import { hexToBech32 } from "SnortUtils"; -import { MetadataCache } from "Cache"; import { UserCache } from "Cache/UserCache"; import messages from "./messages"; diff --git a/packages/app/src/Element/Thread.tsx b/packages/app/src/Element/Thread.tsx index 2d252382..f30f8966 100644 --- a/packages/app/src/Element/Thread.tsx +++ b/packages/app/src/Element/Thread.tsx @@ -2,10 +2,17 @@ import "./Thread.css"; import { useMemo, useState, ReactNode } from "react"; import { useIntl } from "react-intl"; import { useNavigate, useLocation, Link, useParams } from "react-router-dom"; -import { TaggedRawEvent, u256, EventKind, NostrPrefix } from "System"; -import { EventExt, Thread as ThreadInfo } from "System/EventExt"; +import { + TaggedRawEvent, + u256, + EventKind, + NostrPrefix, + EventExt, + Thread as ThreadInfo, + parseNostrLink, +} from "@snort/system"; -import { eventLink, unwrap, getReactions, parseNostrLink, getAllReactions, findTag } from "SnortUtils"; +import { eventLink, unwrap, getReactions, getAllReactions, findTag } from "SnortUtils"; import BackButton from "Element/BackButton"; import Note from "Element/Note"; import NoteGhost from "Element/NoteGhost"; diff --git a/packages/app/src/Element/Timeline.tsx b/packages/app/src/Element/Timeline.tsx index 1159b1b9..6aa8401e 100644 --- a/packages/app/src/Element/Timeline.tsx +++ b/packages/app/src/Element/Timeline.tsx @@ -2,7 +2,7 @@ import "./Timeline.css"; import { FormattedMessage } from "react-intl"; import { useCallback, useMemo } from "react"; import { useInView } from "react-intersection-observer"; -import { TaggedRawEvent, EventKind, u256 } from "System"; +import { TaggedRawEvent, EventKind, u256 } from "@snort/system"; import Icon from "Icons/Icon"; import { dedupeByPubkey, findTag, tagFilterOfTextRepost } from "SnortUtils"; diff --git a/packages/app/src/Element/TrendingPosts.tsx b/packages/app/src/Element/TrendingPosts.tsx index c46c6e73..863174e6 100644 --- a/packages/app/src/Element/TrendingPosts.tsx +++ b/packages/app/src/Element/TrendingPosts.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { NostrEvent, TaggedRawEvent } from "System"; +import { NostrEvent, TaggedRawEvent } from "@snort/system"; import { FormattedMessage } from "react-intl"; import PageSpinner from "Element/PageSpinner"; diff --git a/packages/app/src/Element/TrendingUsers.tsx b/packages/app/src/Element/TrendingUsers.tsx index 9460b8ab..665acc89 100644 --- a/packages/app/src/Element/TrendingUsers.tsx +++ b/packages/app/src/Element/TrendingUsers.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { FormattedMessage } from "react-intl"; import FollowListBase from "Element/FollowListBase"; diff --git a/packages/app/src/Element/Username.tsx b/packages/app/src/Element/Username.tsx index 47a12ca7..3235cd7d 100644 --- a/packages/app/src/Element/Username.tsx +++ b/packages/app/src/Element/Username.tsx @@ -1,7 +1,7 @@ import { MouseEvent } from "react"; import { useNavigate, Link } from "react-router-dom"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import { profileLink } from "SnortUtils"; diff --git a/packages/app/src/Element/WriteDm.tsx b/packages/app/src/Element/WriteDm.tsx index 445437bd..e060c1f7 100644 --- a/packages/app/src/Element/WriteDm.tsx +++ b/packages/app/src/Element/WriteDm.tsx @@ -1,4 +1,4 @@ -import { encodeTLV, NostrPrefix, NostrEvent } from "System"; +import { encodeTLV, NostrPrefix, NostrEvent } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import Icon from "Icons/Icon"; import Spinner from "Icons/Spinner"; diff --git a/packages/app/src/Element/Zap.tsx b/packages/app/src/Element/Zap.tsx index 6a84212b..cb59eee1 100644 --- a/packages/app/src/Element/Zap.tsx +++ b/packages/app/src/Element/Zap.tsx @@ -1,7 +1,7 @@ import "./Zap.css"; import { useMemo } from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import { HexKey, TaggedRawEvent } from "System"; +import { HexKey, TaggedRawEvent } from "@snort/system"; import { decodeInvoice, InvoiceDetails, sha256, unwrap } from "SnortUtils"; import { formatShort } from "Number"; diff --git a/packages/app/src/Element/ZapButton.tsx b/packages/app/src/Element/ZapButton.tsx index ef460d7d..1910fda1 100644 --- a/packages/app/src/Element/ZapButton.tsx +++ b/packages/app/src/Element/ZapButton.tsx @@ -1,6 +1,6 @@ import "./ZapButton.css"; import { useState } from "react"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { useUserProfile } from "Hooks/useUserProfile"; import SendSats from "Element/SendSats"; diff --git a/packages/app/src/Element/ZapstrEmbed.tsx b/packages/app/src/Element/ZapstrEmbed.tsx index d5ca7f01..844b5b67 100644 --- a/packages/app/src/Element/ZapstrEmbed.tsx +++ b/packages/app/src/Element/ZapstrEmbed.tsx @@ -1,6 +1,6 @@ import "./ZapstrEmbed.css"; import { Link } from "react-router-dom"; -import { encodeTLV, NostrPrefix, NostrEvent } from "System"; +import { encodeTLV, NostrPrefix, NostrEvent } from "@snort/system"; import { ProxyImg } from "Element/ProxyImg"; import ProfileImage from "Element/ProfileImage"; diff --git a/packages/app/src/External/NostrBand.ts b/packages/app/src/External/NostrBand.ts index 8615b61e..8553a460 100644 --- a/packages/app/src/External/NostrBand.ts +++ b/packages/app/src/External/NostrBand.ts @@ -1,4 +1,4 @@ -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; export interface TrendingUser { pubkey: string; diff --git a/packages/app/src/Feed/BadgesFeed.ts b/packages/app/src/Feed/BadgesFeed.ts index baf0bacf..8397f8ce 100644 --- a/packages/app/src/Feed/BadgesFeed.ts +++ b/packages/app/src/Feed/BadgesFeed.ts @@ -1,9 +1,7 @@ import { useMemo } from "react"; -import { EventKind, HexKey, Lists } from "System"; +import { EventKind, HexKey, Lists, RequestBuilder, FlatNoteStore, ReplaceableNoteStore } from "@snort/system"; import { unwrap, findTag, chunks } from "SnortUtils"; -import { RequestBuilder } from "System"; -import { FlatNoteStore, ReplaceableNoteStore } from "System/NoteCollection"; import useRequestBuilder from "Hooks/useRequestBuilder"; type BadgeAwards = { diff --git a/packages/app/src/Feed/BookmarkFeed.tsx b/packages/app/src/Feed/BookmarkFeed.tsx index 647cd5b0..2c7da28e 100644 --- a/packages/app/src/Feed/BookmarkFeed.tsx +++ b/packages/app/src/Feed/BookmarkFeed.tsx @@ -1,4 +1,4 @@ -import { HexKey, Lists } from "System"; +import { HexKey, Lists } from "@snort/system"; import useNotelistSubscription from "Hooks/useNotelistSubscription"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/EventFeed.ts b/packages/app/src/Feed/EventFeed.ts index 6ee13f7a..2c295271 100644 --- a/packages/app/src/Feed/EventFeed.ts +++ b/packages/app/src/Feed/EventFeed.ts @@ -1,9 +1,8 @@ import { useMemo } from "react"; -import { NostrPrefix } from "System"; +import { NostrPrefix, RequestBuilder, ReplaceableNoteStore, NostrLink } from "@snort/system"; import useRequestBuilder from "Hooks/useRequestBuilder"; -import { RequestBuilder, ReplaceableNoteStore } from "System"; -import { NostrLink, unwrap } from "SnortUtils"; +import { unwrap } from "SnortUtils"; export default function useEventFeed(link: NostrLink) { const sub = useMemo(() => { diff --git a/packages/app/src/Feed/EventPublisher.ts b/packages/app/src/Feed/EventPublisher.ts index e2eef45c..ff238977 100644 --- a/packages/app/src/Feed/EventPublisher.ts +++ b/packages/app/src/Feed/EventPublisher.ts @@ -1,6 +1,6 @@ import { useMemo } from "react"; import useLogin from "Hooks/useLogin"; -import { EventPublisher } from "System/EventPublisher"; +import { EventPublisher } from "@snort/system"; import { System } from "index"; export default function useEventPublisher() { diff --git a/packages/app/src/Feed/FollowersFeed.ts b/packages/app/src/Feed/FollowersFeed.ts index e8095bce..dc2f79b8 100644 --- a/packages/app/src/Feed/FollowersFeed.ts +++ b/packages/app/src/Feed/FollowersFeed.ts @@ -1,7 +1,6 @@ import { useMemo } from "react"; -import { HexKey, EventKind } from "System"; +import { HexKey, EventKind, PubkeyReplaceableNoteStore, RequestBuilder } from "@snort/system"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useFollowersFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Feed/FollowsFeed.ts b/packages/app/src/Feed/FollowsFeed.ts index b20bef55..5f7b260b 100644 --- a/packages/app/src/Feed/FollowsFeed.ts +++ b/packages/app/src/Feed/FollowsFeed.ts @@ -1,7 +1,6 @@ import { useMemo } from "react"; -import { HexKey, TaggedRawEvent, EventKind } from "System"; +import { HexKey, TaggedRawEvent, EventKind, PubkeyReplaceableNoteStore, RequestBuilder } from "@snort/system"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/LoginFeed.ts b/packages/app/src/Feed/LoginFeed.ts index bf214d7d..bf4a71b6 100644 --- a/packages/app/src/Feed/LoginFeed.ts +++ b/packages/app/src/Feed/LoginFeed.ts @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react"; -import { TaggedRawEvent, Lists, EventKind } from "System"; +import { TaggedRawEvent, Lists, EventKind, FlatNoteStore, RequestBuilder } from "@snort/system"; import debug from "debug"; import { bech32ToHex, getNewest, getNewestEventTagsByKey, unwrap } from "SnortUtils"; @@ -7,7 +7,6 @@ import { makeNotification, sendNotification } from "Notifications"; import useEventPublisher from "Feed/EventPublisher"; import { getMutedKeys } from "Feed/MuteList"; import useModeration from "Hooks/useModeration"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import { DmCache } from "Cache"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/MuteList.ts b/packages/app/src/Feed/MuteList.ts index 3338c496..5e7c75d5 100644 --- a/packages/app/src/Feed/MuteList.ts +++ b/packages/app/src/Feed/MuteList.ts @@ -1,8 +1,14 @@ import { useMemo } from "react"; -import { HexKey, TaggedRawEvent, Lists, EventKind } from "System"; +import { + HexKey, + TaggedRawEvent, + Lists, + EventKind, + ParameterizedReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; import { getNewest } from "SnortUtils"; -import { ParameterizedReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/PinnedFeed.tsx b/packages/app/src/Feed/PinnedFeed.tsx index f55fe40d..bd714903 100644 --- a/packages/app/src/Feed/PinnedFeed.tsx +++ b/packages/app/src/Feed/PinnedFeed.tsx @@ -1,4 +1,4 @@ -import { HexKey, Lists } from "System"; +import { HexKey, Lists } from "@snort/system"; import useNotelistSubscription from "Hooks/useNotelistSubscription"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/RelaysFeed.tsx b/packages/app/src/Feed/RelaysFeed.tsx index 677f5586..e6fe274e 100644 --- a/packages/app/src/Feed/RelaysFeed.tsx +++ b/packages/app/src/Feed/RelaysFeed.tsx @@ -1,8 +1,6 @@ import { useMemo } from "react"; -import { HexKey, FullRelaySettings, EventKind } from "System"; +import { HexKey, FullRelaySettings, EventKind, RequestBuilder, ReplaceableNoteStore } from "@snort/system"; -import { RequestBuilder } from "System"; -import { ReplaceableNoteStore } from "System/NoteCollection"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useRelaysFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Feed/RelaysFeedFollows.tsx b/packages/app/src/Feed/RelaysFeedFollows.tsx index 128fe11f..77367f4d 100644 --- a/packages/app/src/Feed/RelaysFeedFollows.tsx +++ b/packages/app/src/Feed/RelaysFeedFollows.tsx @@ -1,9 +1,16 @@ import { useMemo } from "react"; -import { HexKey, FullRelaySettings, TaggedRawEvent, RelaySettings, EventKind } from "System"; +import { + HexKey, + FullRelaySettings, + TaggedRawEvent, + RelaySettings, + EventKind, + PubkeyReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; import debug from "debug"; import { sanitizeRelayUrl } from "SnortUtils"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import { UserRelays } from "Cache/UserRelayCache"; diff --git a/packages/app/src/Feed/ThreadFeed.ts b/packages/app/src/Feed/ThreadFeed.ts index adbc14f9..1b0af776 100644 --- a/packages/app/src/Feed/ThreadFeed.ts +++ b/packages/app/src/Feed/ThreadFeed.ts @@ -1,8 +1,7 @@ import { useEffect, useMemo, useState } from "react"; -import { u256, EventKind } from "System"; +import { u256, EventKind, NostrLink, FlatNoteStore, RequestBuilder } from "@snort/system"; -import { appendDedupe, NostrLink } from "SnortUtils"; -import { FlatNoteStore, RequestBuilder } from "System"; +import { appendDedupe } from "SnortUtils"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index 8fb8693f..9b8e439b 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -1,8 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import { EventKind, u256 } from "System"; +import { EventKind, u256, FlatNoteStore, RequestBuilder } from "@snort/system"; import { unixNow, unwrap, tagFilterOfTextRepost } from "SnortUtils"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useTimelineWindow from "Hooks/useTimelineWindow"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Feed/ZapsFeed.ts b/packages/app/src/Feed/ZapsFeed.ts index 88694a5e..6fd52ba4 100644 --- a/packages/app/src/Feed/ZapsFeed.ts +++ b/packages/app/src/Feed/ZapsFeed.ts @@ -1,8 +1,7 @@ import { useMemo } from "react"; -import { HexKey, EventKind } from "System"; +import { HexKey, EventKind, FlatNoteStore, RequestBuilder } from "@snort/system"; import { parseZap } from "Element/Zap"; -import { FlatNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; export default function useZapsFeed(pubkey?: HexKey) { diff --git a/packages/app/src/Hooks/useInteractionCache.tsx b/packages/app/src/Hooks/useInteractionCache.tsx index b75e9bf0..46a7521d 100644 --- a/packages/app/src/Hooks/useInteractionCache.tsx +++ b/packages/app/src/Hooks/useInteractionCache.tsx @@ -1,5 +1,5 @@ import { useSyncExternalStore } from "react"; -import { HexKey, u256 } from "System"; +import { HexKey, u256 } from "@snort/system"; import { InteractionCache } from "Cache/EventInteractionCache"; import { EventInteraction } from "Db"; diff --git a/packages/app/src/Hooks/useModeration.tsx b/packages/app/src/Hooks/useModeration.tsx index 2cbd3c7a..3a530c5a 100644 --- a/packages/app/src/Hooks/useModeration.tsx +++ b/packages/app/src/Hooks/useModeration.tsx @@ -1,4 +1,4 @@ -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import useLogin from "Hooks/useLogin"; import { setBlocked, setMuted } from "Login"; diff --git a/packages/app/src/Hooks/useNotelistSubscription.ts b/packages/app/src/Hooks/useNotelistSubscription.ts index 55aa7f95..f9e1eee2 100644 --- a/packages/app/src/Hooks/useNotelistSubscription.ts +++ b/packages/app/src/Hooks/useNotelistSubscription.ts @@ -1,7 +1,13 @@ import { useMemo } from "react"; -import { HexKey, Lists, EventKind } from "System"; +import { + HexKey, + Lists, + EventKind, + FlatNoteStore, + ParameterizedReplaceableNoteStore, + RequestBuilder, +} from "@snort/system"; -import { FlatNoteStore, ParameterizedReplaceableNoteStore, RequestBuilder } from "System"; import useRequestBuilder from "Hooks/useRequestBuilder"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Hooks/useRequestBuilder.tsx b/packages/app/src/Hooks/useRequestBuilder.tsx index 6d2fb8a7..d982ed9c 100644 --- a/packages/app/src/Hooks/useRequestBuilder.tsx +++ b/packages/app/src/Hooks/useRequestBuilder.tsx @@ -1,6 +1,5 @@ import { useSyncExternalStore } from "react"; -import { RequestBuilder } from "System"; -import { EmptySnapshot, NoteStore, StoreSnapshot } from "System/NoteCollection"; +import { RequestBuilder, EmptySnapshot, NoteStore, StoreSnapshot } from "@snort/system"; import { unwrap } from "SnortUtils"; import { System } from "index"; diff --git a/packages/app/src/Hooks/useSystemState.tsx b/packages/app/src/Hooks/useSystemState.tsx index 971675be..78932907 100644 --- a/packages/app/src/Hooks/useSystemState.tsx +++ b/packages/app/src/Hooks/useSystemState.tsx @@ -1,5 +1,5 @@ import { useSyncExternalStore } from "react"; -import { SystemSnapshot } from "System"; +import { SystemSnapshot } from "@snort/system"; import { System } from "index"; export default function useSystemState() { diff --git a/packages/app/src/Hooks/useUserProfile.ts b/packages/app/src/Hooks/useUserProfile.ts index 42d68310..3909774a 100644 --- a/packages/app/src/Hooks/useUserProfile.ts +++ b/packages/app/src/Hooks/useUserProfile.ts @@ -1,7 +1,6 @@ import { useEffect, useSyncExternalStore } from "react"; -import { HexKey } from "System"; -import { MetadataCache } from "Cache"; +import { HexKey, MetadataCache } from "@snort/system"; import { UserCache } from "Cache/UserCache"; import { ProfileLoader } from "index"; diff --git a/packages/app/src/LNURL.ts b/packages/app/src/LNURL.ts index 4138bb93..42978610 100644 --- a/packages/app/src/LNURL.ts +++ b/packages/app/src/LNURL.ts @@ -1,4 +1,4 @@ -import { HexKey, NostrEvent } from "System"; +import { HexKey, NostrEvent } from "@snort/system"; import { EmailRegex } from "Const"; import { bech32ToText, unwrap } from "SnortUtils"; diff --git a/packages/app/src/Login/Functions.ts b/packages/app/src/Login/Functions.ts index ac9c37f2..1ba6ffcf 100644 --- a/packages/app/src/Login/Functions.ts +++ b/packages/app/src/Login/Functions.ts @@ -1,4 +1,4 @@ -import { HexKey, RelaySettings } from "System"; +import { HexKey, RelaySettings, EventPublisher } from "@snort/system"; import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; @@ -7,7 +7,6 @@ import { LoginStore, UserPreferences, LoginSession } from "Login"; import { generateBip39Entropy, entropyToPrivateKey } from "nip6"; import { bech32ToHex, dedupeById, randomSample, sanitizeRelayUrl, unixNowMs, unwrap } from "SnortUtils"; import { SubscriptionEvent } from "Subscription"; -import { EventPublisher } from "System/EventPublisher"; import { System } from "index"; export function setRelays(state: LoginSession, relays: Record, createdAt: number) { diff --git a/packages/app/src/Login/LoginSession.ts b/packages/app/src/Login/LoginSession.ts index 95736dd6..3a7fb288 100644 --- a/packages/app/src/Login/LoginSession.ts +++ b/packages/app/src/Login/LoginSession.ts @@ -1,4 +1,4 @@ -import { HexKey, RelaySettings, u256 } from "System"; +import { HexKey, RelaySettings, u256 } from "@snort/system"; import { UserPreferences } from "Login"; import { SubscriptionEvent } from "Subscription"; diff --git a/packages/app/src/Login/MultiAccountStore.ts b/packages/app/src/Login/MultiAccountStore.ts index ddbb4a02..70faea98 100644 --- a/packages/app/src/Login/MultiAccountStore.ts +++ b/packages/app/src/Login/MultiAccountStore.ts @@ -1,7 +1,7 @@ import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; -import { HexKey, RelaySettings } from "System"; +import { HexKey, RelaySettings } from "@snort/system"; import { DefaultRelays } from "Const"; import ExternalStore from "ExternalStore"; diff --git a/packages/app/src/Nip05/SnortServiceProvider.ts b/packages/app/src/Nip05/SnortServiceProvider.ts index fe23ef2a..d6efa314 100644 --- a/packages/app/src/Nip05/SnortServiceProvider.ts +++ b/packages/app/src/Nip05/SnortServiceProvider.ts @@ -1,5 +1,4 @@ -import { EventKind } from "System"; -import { EventPublisher } from "System/EventPublisher"; +import { EventKind, EventPublisher } from "@snort/system"; import { ServiceError, ServiceProvider } from "./ServiceProvider"; export interface ManageHandle { diff --git a/packages/app/src/Notifications.ts b/packages/app/src/Notifications.ts index 09360995..46a4fdef 100644 --- a/packages/app/src/Notifications.ts +++ b/packages/app/src/Notifications.ts @@ -1,7 +1,6 @@ import Nostrich from "nostrich.webp"; -import { TaggedRawEvent, EventKind } from "System"; -import { MetadataCache } from "Cache"; +import { TaggedRawEvent, EventKind, MetadataCache } from "@snort/system"; import { getDisplayName } from "Element/ProfileImage"; import { MentionRegex } from "Const"; import { tagFilterOfTextRepost, unwrap } from "SnortUtils"; diff --git a/packages/app/src/Pages/DonatePage.tsx b/packages/app/src/Pages/DonatePage.tsx index b871f7ac..64517db8 100644 --- a/packages/app/src/Pages/DonatePage.tsx +++ b/packages/app/src/Pages/DonatePage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { ApiHost, KieranPubKey, SnortPubKey } from "Const"; import ProfilePreview from "Element/ProfilePreview"; diff --git a/packages/app/src/Pages/LoginPage.tsx b/packages/app/src/Pages/LoginPage.tsx index faf6e957..be38fea4 100644 --- a/packages/app/src/Pages/LoginPage.tsx +++ b/packages/app/src/Pages/LoginPage.tsx @@ -3,7 +3,7 @@ import "./LoginPage.css"; import { CSSProperties, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useIntl, FormattedMessage } from "react-intl"; -import { HexKey } from "System"; +import { HexKey } from "@snort/system"; import { bech32ToHex, unwrap } from "SnortUtils"; import ZapButton from "Element/ZapButton"; diff --git a/packages/app/src/Pages/MessagesPage.tsx b/packages/app/src/Pages/MessagesPage.tsx index 34f83c7d..3aa0e6e4 100644 --- a/packages/app/src/Pages/MessagesPage.tsx +++ b/packages/app/src/Pages/MessagesPage.tsx @@ -1,7 +1,7 @@ import React, { useMemo, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useNavigate } from "react-router-dom"; -import { HexKey, NostrEvent, NostrPrefix } from "System"; +import { HexKey, NostrEvent, NostrPrefix } from "@snort/system"; import UnreadCount from "Element/UnreadCount"; import ProfileImage, { getDisplayName } from "Element/ProfileImage"; diff --git a/packages/app/src/Pages/NostrLinkHandler.tsx b/packages/app/src/Pages/NostrLinkHandler.tsx index 3a4d966d..ea8f57c5 100644 --- a/packages/app/src/Pages/NostrLinkHandler.tsx +++ b/packages/app/src/Pages/NostrLinkHandler.tsx @@ -1,10 +1,10 @@ -import { NostrPrefix } from "System"; +import { NostrPrefix, parseNostrLink } from "@snort/system"; import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; import Spinner from "Icons/Spinner"; -import { parseNostrLink, profileLink } from "SnortUtils"; +import { profileLink } from "SnortUtils"; import { getNip05PubKey } from "Pages/LoginPage"; export default function NostrLinkHandler() { diff --git a/packages/app/src/Pages/ProfilePage.tsx b/packages/app/src/Pages/ProfilePage.tsx index 25adf365..551b0c8f 100644 --- a/packages/app/src/Pages/ProfilePage.tsx +++ b/packages/app/src/Pages/ProfilePage.tsx @@ -2,9 +2,9 @@ import "./ProfilePage.css"; import { useEffect, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; -import { encodeTLV, EventKind, HexKey, NostrPrefix } from "System"; +import { encodeTLV, EventKind, HexKey, NostrPrefix, parseNostrLink } from "@snort/system"; -import { parseNostrLink, getReactions, unwrap } from "SnortUtils"; +import { getReactions, unwrap } from "SnortUtils"; import { formatShort } from "Number"; import Note from "Element/Note"; import Bookmarks from "Element/Bookmarks"; diff --git a/packages/app/src/Pages/new/ProfileSetup.tsx b/packages/app/src/Pages/new/ProfileSetup.tsx index 20d6864d..26f5f23a 100644 --- a/packages/app/src/Pages/new/ProfileSetup.tsx +++ b/packages/app/src/Pages/new/ProfileSetup.tsx @@ -1,12 +1,13 @@ import { useEffect, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { mapEventToProfile } from "@snort/system"; import Logo from "Element/Logo"; import useEventPublisher from "Feed/EventPublisher"; import useLogin from "Hooks/useLogin"; import { useUserProfile } from "Hooks/useUserProfile"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import AvatarEditor from "Element/AvatarEditor"; import messages from "./messages"; diff --git a/packages/app/src/Pages/settings/Keys.tsx b/packages/app/src/Pages/settings/Keys.tsx index d8871bcc..00958e95 100644 --- a/packages/app/src/Pages/settings/Keys.tsx +++ b/packages/app/src/Pages/settings/Keys.tsx @@ -1,6 +1,6 @@ import "./Keys.css"; import { FormattedMessage } from "react-intl"; -import { encodeTLV, NostrPrefix } from "System"; +import { encodeTLV, NostrPrefix } from "@snort/system"; import Copy from "Element/Copy"; import useLogin from "Hooks/useLogin"; diff --git a/packages/app/src/Pages/settings/Profile.tsx b/packages/app/src/Pages/settings/Profile.tsx index 5ce684e4..1918036c 100644 --- a/packages/app/src/Pages/settings/Profile.tsx +++ b/packages/app/src/Pages/settings/Profile.tsx @@ -3,13 +3,14 @@ import Nostrich from "nostrich.webp"; import { useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; import { useNavigate } from "react-router-dom"; +import { mapEventToProfile } from "@snort/system"; import useEventPublisher from "Feed/EventPublisher"; import { useUserProfile } from "Hooks/useUserProfile"; import { openFile } from "SnortUtils"; import useFileUpload from "Upload"; import AsyncButton from "Element/AsyncButton"; -import { mapEventToProfile, UserCache } from "Cache"; +import { UserCache } from "Cache"; import useLogin from "Hooks/useLogin"; import AvatarEditor from "Element/AvatarEditor"; import Icon from "Icons/Icon"; diff --git a/packages/app/src/Pages/settings/Relays.tsx b/packages/app/src/Pages/settings/Relays.tsx index 78b490c7..d5338309 100644 --- a/packages/app/src/Pages/settings/Relays.tsx +++ b/packages/app/src/Pages/settings/Relays.tsx @@ -23,7 +23,6 @@ const RelaySettingsPage = () => { if (publisher) { const ev = await publisher.contactList(login.follows.item, login.relays.item); publisher.broadcast(ev); - publisher.broadcastForBootstrap(ev); try { const onlineRelays = await fetch("https://api.nostr.watch/v1/online").then(r => r.json()); const relayList = await publisher.relayList(login.relays.item); diff --git a/packages/app/src/SnortApi.ts b/packages/app/src/SnortApi.ts index 75dde20a..498346f1 100644 --- a/packages/app/src/SnortApi.ts +++ b/packages/app/src/SnortApi.ts @@ -1,7 +1,6 @@ -import { EventKind } from "System"; +import { EventKind, EventPublisher } from "@snort/system"; import { ApiHost } from "Const"; import { SubscriptionType } from "Subscription"; -import { EventPublisher } from "System/EventPublisher"; export interface RevenueToday { donations: number; diff --git a/packages/app/src/SnortUtils/Utils.test.ts b/packages/app/src/SnortUtils/Utils.test.ts index e40c6979..b91d02ae 100644 --- a/packages/app/src/SnortUtils/Utils.test.ts +++ b/packages/app/src/SnortUtils/Utils.test.ts @@ -1,5 +1,4 @@ -import { NostrPrefix } from "System"; -import { parseNostrLink, tryParseNostrLink } from "."; +import { NostrPrefix } from "@snort/system"; import { splitByUrl, magnetURIDecode, getRelayName } from "."; import { describe, expect } from "@jest/globals"; @@ -93,47 +92,3 @@ describe("getRelayName", () => { expect(output).toEqual("relay.example2.com?broadcast=true"); }); }); - -describe("tryParseNostrLink", () => { - it("is a valid nostr link", () => { - expect(parseNostrLink("nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ - id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", - type: NostrPrefix.PublicKey, - }); - expect(parseNostrLink("web+nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ - id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", - type: NostrPrefix.PublicKey, - }); - expect(parseNostrLink("nostr:note15449edq4qa5wzgqvh8td0q0dp6hwtes4pknsrm7eygeenhlj99xsq94wu9")).toMatchObject({ - id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", - type: NostrPrefix.Note, - }); - expect( - parseNostrLink( - "nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p" - ) - ).toMatchObject({ - id: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", - type: NostrPrefix.Profile, - relays: ["wss://r.x.com", "wss://djbas.sadkb.com"], - }); - expect(parseNostrLink("nostr:nevent1qqs226juks2sw68pyqxtn4khs8ksath9uc2smfcpalvjyvuemlezjngrd87dq")).toMatchObject({ - id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", - type: NostrPrefix.Event, - }); - expect( - parseNostrLink( - "nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu" - ) - ).toMatchObject({ - id: "ipsum", - type: NostrPrefix.Address, - relays: ["wss://relay.nostr.org"], - author: "a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919", - kind: 30023, - }); - }); - test.each(["nostr:npub", "web+nostr:npub", "nostr:nevent1xxx"])("should return false for invalid nostr links", lb => { - expect(tryParseNostrLink(lb)).toBeUndefined(); - }); -}); diff --git a/packages/app/src/SnortUtils/index.ts b/packages/app/src/SnortUtils/index.ts index 5ff04ed4..df89d9f5 100644 --- a/packages/app/src/SnortUtils/index.ts +++ b/packages/app/src/SnortUtils/index.ts @@ -13,12 +13,9 @@ import { EventKind, encodeTLV, NostrPrefix, - decodeTLV, - TLVEntryType, NostrEvent, -} from "System"; -import { MetadataCache } from "Cache"; -import NostrLink from "Element/NostrLink"; + MetadataCache, +} from "@snort/system"; export const sha256 = (str: string | Uint8Array): u256 => { return utils.bytesToHex(hash(str)); @@ -506,113 +503,6 @@ export function getUrlHostname(url?: string) { } } -export interface NostrLink { - type: NostrPrefix; - id: string; - kind?: number; - author?: string; - relays?: Array; - encode(): string; -} - -export function validateNostrLink(link: string): boolean { - try { - const parsedLink = parseNostrLink(link); - if (!parsedLink) { - return false; - } - if (parsedLink.type === NostrPrefix.PublicKey || parsedLink.type === NostrPrefix.Note) { - return parsedLink.id.length === 64; - } - - return true; - } catch { - return false; - } -} - -export function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined { - try { - return parseNostrLink(link, prefixHint); - } catch { - return undefined; - } -} - -export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink { - const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; - - const isPrefix = (prefix: NostrPrefix) => { - return entity.startsWith(prefix); - }; - - if (isPrefix(NostrPrefix.PublicKey)) { - const id = bech32ToHex(entity); - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.PublicKey, - id: id, - encode: () => hexToBech32(NostrPrefix.PublicKey, id), - }; - } else if (isPrefix(NostrPrefix.Note)) { - const id = bech32ToHex(entity); - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Note, - id: id, - encode: () => hexToBech32(NostrPrefix.Note, id), - }; - } else if (isPrefix(NostrPrefix.Profile) || isPrefix(NostrPrefix.Event) || isPrefix(NostrPrefix.Address)) { - const decoded = decodeTLV(entity); - - const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string; - const relays = decoded.filter(a => a.type === TLVEntryType.Relay).map(a => a.value as string); - const author = decoded.find(a => a.type === TLVEntryType.Author)?.value as string; - const kind = decoded.find(a => a.type === TLVEntryType.Kind)?.value as number; - - const encode = () => { - return entity; // return original - }; - if (isPrefix(NostrPrefix.Profile)) { - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Profile, - id, - relays, - kind, - author, - encode, - }; - } else if (isPrefix(NostrPrefix.Event)) { - if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); - return { - type: NostrPrefix.Event, - id, - relays, - kind, - author, - encode, - }; - } else if (isPrefix(NostrPrefix.Address)) { - return { - type: NostrPrefix.Address, - id, - relays, - kind, - author, - encode, - }; - } - } else if (prefixHint) { - return { - type: prefixHint, - id: link, - encode: () => hexToBech32(prefixHint, link), - }; - } - throw new Error("Invalid nostr link"); -} - export function sanitizeRelayUrl(url: string) { try { return new URL(url).toString(); diff --git a/packages/app/src/State/NoteCreator.ts b/packages/app/src/State/NoteCreator.ts index f0bf02fd..e6a8dda8 100644 --- a/packages/app/src/State/NoteCreator.ts +++ b/packages/app/src/State/NoteCreator.ts @@ -1,5 +1,5 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { NostrEvent, TaggedRawEvent } from "System"; +import { NostrEvent, TaggedRawEvent } from "@snort/system"; interface NoteCreatorStore { show: boolean; diff --git a/packages/app/src/State/ReBroadcast.ts b/packages/app/src/State/ReBroadcast.ts index 76d0165d..23cc253b 100644 --- a/packages/app/src/State/ReBroadcast.ts +++ b/packages/app/src/State/ReBroadcast.ts @@ -1,5 +1,5 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; interface ReBroadcastStore { show: boolean; diff --git a/packages/app/src/System/Const.ts b/packages/app/src/System/Const.ts deleted file mode 100644 index e3502ce0..00000000 --- a/packages/app/src/System/Const.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Websocket re-connect timeout - */ -export const DefaultConnectTimeout = 2000; diff --git a/packages/app/src/System/Util.test.ts b/packages/app/src/System/Util.test.ts deleted file mode 100644 index 14812019..00000000 --- a/packages/app/src/System/Util.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { distance } from "./Util"; - -describe("distance", () => { - it("should have 0 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "a", - }; - expect(distance(a, b)).toEqual(0); - }); - it("should have 1 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "b", - }; - expect(distance(a, b)).toEqual(1); - }); - it("should have 10 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "a", - kinds: 1, - }; - expect(distance(a, b)).toEqual(10); - }); - it("should have 11 distance", () => { - const a = { - ids: "a", - }; - const b = { - ids: "b", - kinds: 1, - }; - expect(distance(a, b)).toEqual(11); - }); - it("should have 1 distance, arrays", () => { - const a = { - since: 1, - until: 100, - kinds: [1], - authors: ["kieran", "snort", "c", "d", "e"], - }; - const b = { - since: 1, - until: 100, - kinds: [6969], - authors: ["kieran", "snort", "c", "d", "e"], - }; - expect(distance(a, b)).toEqual(1); - }); - it("should have 1 distance, array change extra", () => { - const a = { - since: 1, - until: 100, - kinds: [1], - authors: ["f", "kieran", "snort", "c", "d"], - }; - const b = { - since: 1, - until: 100, - kinds: [1], - authors: ["kieran", "snort", "c", "d", "e"], - }; - expect(distance(a, b)).toEqual(1); - }); -}); diff --git a/packages/app/src/Tasks/Nip5Task.tsx b/packages/app/src/Tasks/Nip5Task.tsx index fd711a24..c737ca61 100644 --- a/packages/app/src/Tasks/Nip5Task.tsx +++ b/packages/app/src/Tasks/Nip5Task.tsx @@ -1,6 +1,6 @@ import { FormattedMessage } from "react-intl"; import { Link } from "react-router-dom"; -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; import { BaseUITask } from "Tasks"; export class Nip5Task extends BaseUITask { diff --git a/packages/app/src/Tasks/index.ts b/packages/app/src/Tasks/index.ts index 384c80af..c966d1e6 100644 --- a/packages/app/src/Tasks/index.ts +++ b/packages/app/src/Tasks/index.ts @@ -1,4 +1,4 @@ -import { MetadataCache } from "Cache"; +import { MetadataCache } from "@snort/system"; export interface UITask { id: string; diff --git a/packages/app/src/Upload/VoidCat.ts b/packages/app/src/Upload/VoidCat.ts index 269d57cc..8eb8a11a 100644 --- a/packages/app/src/Upload/VoidCat.ts +++ b/packages/app/src/Upload/VoidCat.ts @@ -1,8 +1,7 @@ -import { EventKind } from "System"; +import { EventKind, EventPublisher } from "@snort/system"; import { VoidApi } from "@void-cat/api"; import { FileExtensionRegex, VoidCatHost } from "Const"; -import { EventPublisher } from "System/EventPublisher"; import { UploadResult } from "Upload"; import { magnetURIDecode } from "SnortUtils"; diff --git a/packages/app/src/Upload/index.ts b/packages/app/src/Upload/index.ts index 8cf57586..ce993af4 100644 --- a/packages/app/src/Upload/index.ts +++ b/packages/app/src/Upload/index.ts @@ -1,5 +1,5 @@ import useLogin from "Hooks/useLogin"; -import { NostrEvent } from "System"; +import { NostrEvent } from "@snort/system"; import NostrBuild from "Upload/NostrBuild"; import VoidCat from "Upload/VoidCat"; diff --git a/packages/app/src/Wallet/NostrWalletConnect.ts b/packages/app/src/Wallet/NostrWalletConnect.ts index 3b4abe53..8a94a523 100644 --- a/packages/app/src/Wallet/NostrWalletConnect.ts +++ b/packages/app/src/Wallet/NostrWalletConnect.ts @@ -1,6 +1,4 @@ -import { Connection, EventKind, NostrEvent } from "System"; -import { EventBuilder } from "System"; -import { EventExt } from "System/EventExt"; +import { Connection, EventKind, NostrEvent, EventBuilder, EventExt } from "@snort/system"; import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "Wallet"; import debug from "debug"; diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 8dfb2a8a..e7f30e0a 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -33,10 +33,9 @@ import { SubscribeRoutes } from "Pages/subscribe"; import ZapPoolPage from "Pages/ZapPool"; import DebugPage from "Pages/Debug"; import { db } from "Db"; -import { preload } from "Cache"; +import { preload, UserCache } from "Cache"; import { LoginStore } from "Login"; -import { ProfileLoaderService } from "System/ProfileCache"; -import { NostrSystem } from "System"; +import { NostrSystem, ProfileLoaderService } from "@snort/system"; import { UserRelays } from "Cache/UserRelayCache"; /** @@ -49,7 +48,7 @@ export const System = new NostrSystem({ /** * Singleton user profile loader */ -export const ProfileLoader = new ProfileLoaderService(System); +export const ProfileLoader = new ProfileLoaderService(System, UserCache); // @ts-expect-error Setting webpack nonce window.__webpack_nonce__ = "ZmlhdGphZiBzYWlkIHNub3J0LnNvY2lhbCBpcyBwcmV0dHkgZ29vZCwgd2UgbWFkZSBpdCE="; diff --git a/packages/system/.npmignore b/packages/system/.npmignore new file mode 100644 index 00000000..9b5e52ea --- /dev/null +++ b/packages/system/.npmignore @@ -0,0 +1,5 @@ +tests/ +src/ +*.tgz +jest.config.js +worker.ts \ No newline at end of file diff --git a/packages/system/dist/Connection.d.ts b/packages/system/dist/Connection.d.ts new file mode 100644 index 00000000..b8205e0c --- /dev/null +++ b/packages/system/dist/Connection.d.ts @@ -0,0 +1,90 @@ +import { ConnectionStats } from "./ConnectionStats"; +import { NostrEvent, ReqCommand, TaggedRawEvent, u256 } from "./Nostr"; +import { RelayInfo } from "./RelayInfo"; +import ExternalStore from "./ExternalStore"; +export type AuthHandler = (challenge: string, relay: string) => Promise; +/** + * Relay settings + */ +export interface RelaySettings { + read: boolean; + write: boolean; +} +/** + * Snapshot of connection stats + */ +export interface ConnectionStateSnapshot { + connected: boolean; + disconnects: number; + avgLatency: number; + events: { + received: number; + send: number; + }; + settings?: RelaySettings; + info?: RelayInfo; + pendingRequests: Array; + activeRequests: Array; + id: string; + ephemeral: boolean; + address: string; +} +export declare class Connection extends ExternalStore { + #private; + Id: string; + Address: string; + Socket: WebSocket | null; + PendingRaw: Array; + PendingRequests: Array<{ + cmd: ReqCommand; + cb: () => void; + }>; + ActiveRequests: Set; + Settings: RelaySettings; + Info?: RelayInfo; + ConnectTimeout: number; + Stats: ConnectionStats; + HasStateChange: boolean; + IsClosed: boolean; + ReconnectTimer: ReturnType | null; + EventsCallback: Map void>; + OnConnected?: () => void; + OnEvent?: (sub: string, e: TaggedRawEvent) => void; + OnEose?: (sub: string) => void; + OnDisconnect?: (id: string) => void; + Auth?: AuthHandler; + AwaitingAuth: Map; + Authed: boolean; + Ephemeral: boolean; + EphemeralTimeout: ReturnType | undefined; + Down: boolean; + constructor(addr: string, options: RelaySettings, auth?: AuthHandler, ephemeral?: boolean); + ResetEphemeralTimeout(): void; + Connect(): Promise; + Close(): void; + OnOpen(): void; + OnClose(e: CloseEvent): void; + OnMessage(e: MessageEvent): void; + OnError(e: Event): void; + /** + * Send event on this connection + */ + SendEvent(e: NostrEvent): void; + /** + * Send event on this connection and wait for OK response + */ + SendAsync(e: NostrEvent, timeout?: number): Promise; + /** + * Using relay document to determine if this relay supports a feature + */ + SupportsNip(n: number): boolean; + /** + * Queue or send command to the relay + * @param cmd The REQ to send to the server + */ + QueueReq(cmd: ReqCommand, cbSent: () => void): void; + CloseReq(id: string): void; + takeSnapshot(): ConnectionStateSnapshot; + _OnAuthAsync(challenge: string): Promise; +} +//# sourceMappingURL=Connection.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Connection.d.ts.map b/packages/system/dist/Connection.d.ts.map new file mode 100644 index 00000000..61f78755 --- /dev/null +++ b/packages/system/dist/Connection.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../src/Connection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Connection.js b/packages/system/dist/Connection.js new file mode 100644 index 00000000..a33148da --- /dev/null +++ b/packages/system/dist/Connection.js @@ -0,0 +1,343 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _Connection_instances, _Connection_SendQueuedRequests, _Connection_ResetQueues, _Connection_SendJson, _Connection_sendPendingRaw, _Connection_sendOnWire, _Connection_maxSubscriptions_get; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Connection = void 0; +const uuid_1 = require("uuid"); +const Const_1 = require("./Const"); +const ConnectionStats_1 = require("./ConnectionStats"); +const Util_1 = require("./Util"); +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +class Connection extends ExternalStore_1.default { + constructor(addr, options, auth, ephemeral = false) { + super(); + _Connection_instances.add(this); + this.Socket = null; + this.PendingRaw = []; + this.PendingRequests = []; + this.ActiveRequests = new Set(); + this.ConnectTimeout = Const_1.DefaultConnectTimeout; + this.Stats = new ConnectionStats_1.ConnectionStats(); + this.HasStateChange = true; + this.Authed = false; + this.Down = true; + this.Id = (0, uuid_1.v4)(); + this.Address = addr; + this.Settings = options; + this.IsClosed = false; + this.ReconnectTimer = null; + this.EventsCallback = new Map(); + this.AwaitingAuth = new Map(); + this.Auth = auth; + this.Ephemeral = ephemeral; + } + ResetEphemeralTimeout() { + if (this.EphemeralTimeout) { + clearTimeout(this.EphemeralTimeout); + } + if (this.Ephemeral) { + this.EphemeralTimeout = setTimeout(() => { + this.Close(); + }, 30000); + } + } + async Connect() { + try { + if (this.Info === undefined) { + const u = new URL(this.Address); + const rsp = await fetch(`${u.protocol === "wss:" ? "https:" : "http:"}//${u.host}`, { + headers: { + accept: "application/nostr+json", + }, + }); + if (rsp.ok) { + const data = await rsp.json(); + for (const [k, v] of Object.entries(data)) { + if (v === "unset" || v === "" || v === "~") { + data[k] = undefined; + } + } + this.Info = data; + } + } + } + catch (e) { + console.warn("Could not load relay information", e); + } + if (this.Socket) { + this.Id = (0, uuid_1.v4)(); + this.Socket.onopen = null; + this.Socket.onmessage = null; + this.Socket.onerror = null; + this.Socket.onclose = null; + } + this.IsClosed = false; + this.Socket = new WebSocket(this.Address); + this.Socket.onopen = () => this.OnOpen(); + this.Socket.onmessage = e => this.OnMessage(e); + this.Socket.onerror = e => this.OnError(e); + this.Socket.onclose = e => this.OnClose(e); + } + Close() { + this.IsClosed = true; + if (this.ReconnectTimer !== null) { + clearTimeout(this.ReconnectTimer); + this.ReconnectTimer = null; + } + this.Socket?.close(); + this.notifyChange(); + } + OnOpen() { + this.ConnectTimeout = Const_1.DefaultConnectTimeout; + console.log(`[${this.Address}] Open!`); + this.Down = false; + if (this.Ephemeral) { + this.ResetEphemeralTimeout(); + } + this.OnConnected?.(); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this); + } + OnClose(e) { + if (!this.IsClosed) { + this.ConnectTimeout = this.ConnectTimeout * 2; + console.log(`[${this.Address}] Closed (${e.reason}), trying again in ${(this.ConnectTimeout / 1000) + .toFixed(0) + .toLocaleString()} sec`); + this.ReconnectTimer = setTimeout(() => { + this.Connect(); + }, this.ConnectTimeout); + this.Stats.Disconnects++; + } + else { + console.log(`[${this.Address}] Closed!`); + this.ReconnectTimer = null; + } + this.OnDisconnect?.(this.Id); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_ResetQueues).call(this); + // reset connection Id on disconnect, for query-tracking + this.Id = (0, uuid_1.v4)(); + this.notifyChange(); + } + OnMessage(e) { + if (e.data.length > 0) { + const msg = JSON.parse(e.data); + const tag = msg[0]; + switch (tag) { + case "AUTH": { + this._OnAuthAsync(msg[1]) + .then(() => __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this)) + .catch(console.error); + this.Stats.EventsReceived++; + this.notifyChange(); + break; + } + case "EVENT": { + this.OnEvent?.(msg[1], { + ...msg[2], + relays: [this.Address], + }); + this.Stats.EventsReceived++; + this.notifyChange(); + break; + } + case "EOSE": { + this.OnEose?.(msg[1]); + break; + } + case "OK": { + // feedback to broadcast call + console.debug(`${this.Address} OK: `, msg); + const id = msg[1]; + if (this.EventsCallback.has(id)) { + const cb = (0, Util_1.unwrap)(this.EventsCallback.get(id)); + this.EventsCallback.delete(id); + cb(msg); + } + break; + } + case "NOTICE": { + console.warn(`[${this.Address}] NOTICE: ${msg[1]}`); + break; + } + default: { + console.warn(`Unknown tag: ${tag}`); + break; + } + } + } + } + OnError(e) { + console.error(e); + this.notifyChange(); + } + /** + * Send event on this connection + */ + SendEvent(e) { + if (!this.Settings.write) { + return; + } + const req = ["EVENT", e]; + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, req); + this.Stats.EventsSent++; + this.notifyChange(); + } + /** + * Send event on this connection and wait for OK response + */ + async SendAsync(e, timeout = 5000) { + return new Promise(resolve => { + if (!this.Settings.write) { + resolve(); + return; + } + const t = setTimeout(() => { + resolve(); + }, timeout); + this.EventsCallback.set(e.id, () => { + clearTimeout(t); + resolve(); + }); + const req = ["EVENT", e]; + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, req); + this.Stats.EventsSent++; + this.notifyChange(); + }); + } + /** + * Using relay document to determine if this relay supports a feature + */ + SupportsNip(n) { + return this.Info?.supported_nips?.some(a => a === n) ?? false; + } + /** + * Queue or send command to the relay + * @param cmd The REQ to send to the server + */ + QueueReq(cmd, cbSent) { + if (this.ActiveRequests.size >= __classPrivateFieldGet(this, _Connection_instances, "a", _Connection_maxSubscriptions_get)) { + this.PendingRequests.push({ + cmd, + cb: cbSent, + }); + console.debug("Queuing:", this.Address, cmd); + } + else { + this.ActiveRequests.add(cmd[1]); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, cmd); + cbSent(); + } + this.notifyChange(); + } + CloseReq(id) { + if (this.ActiveRequests.delete(id)) { + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, ["CLOSE", id]); + this.OnEose?.(id); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendQueuedRequests).call(this); + } + this.notifyChange(); + } + takeSnapshot() { + return { + connected: this.Socket?.readyState === WebSocket.OPEN, + events: { + received: this.Stats.EventsReceived, + send: this.Stats.EventsSent, + }, + avgLatency: this.Stats.Latency.length > 0 + ? this.Stats.Latency.reduce((acc, v) => acc + v, 0) / this.Stats.Latency.length + : 0, + disconnects: this.Stats.Disconnects, + info: this.Info, + id: this.Id, + pendingRequests: [...this.PendingRequests.map(a => a.cmd[1])], + activeRequests: [...this.ActiveRequests], + ephemeral: this.Ephemeral, + address: this.Address, + }; + } + async _OnAuthAsync(challenge) { + const authCleanup = () => { + this.AwaitingAuth.delete(challenge); + }; + if (!this.Auth) { + throw new Error("Auth hook not registered"); + } + this.AwaitingAuth.set(challenge, true); + const authEvent = await this.Auth(challenge, this.Address); + return new Promise(resolve => { + if (!authEvent) { + authCleanup(); + return Promise.reject("no event"); + } + const t = setTimeout(() => { + authCleanup(); + resolve(); + }, 10000); + this.EventsCallback.set(authEvent.id, (msg) => { + clearTimeout(t); + authCleanup(); + if (msg.length > 3 && msg[2] === true) { + this.Authed = true; + } + resolve(); + }); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, ["AUTH", authEvent]); + }); + } +} +exports.Connection = Connection; +_Connection_instances = new WeakSet(), _Connection_SendQueuedRequests = function _Connection_SendQueuedRequests() { + const canSend = __classPrivateFieldGet(this, _Connection_instances, "a", _Connection_maxSubscriptions_get) - this.ActiveRequests.size; + if (canSend > 0) { + for (let x = 0; x < canSend; x++) { + const p = this.PendingRequests.shift(); + if (p) { + this.ActiveRequests.add(p.cmd[1]); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_SendJson).call(this, p.cmd); + p.cb(); + console.debug("Sent pending REQ", this.Address, p.cmd); + } + } + } +}, _Connection_ResetQueues = function _Connection_ResetQueues() { + this.ActiveRequests.clear(); + this.PendingRequests = []; + this.PendingRaw = []; + this.notifyChange(); +}, _Connection_SendJson = function _Connection_SendJson(obj) { + const authPending = !this.Authed && (this.AwaitingAuth.size > 0 || this.Info?.limitation?.auth_required === true); + if (this.Socket?.readyState !== WebSocket.OPEN || authPending) { + this.PendingRaw.push(obj); + if (this.Socket?.readyState === WebSocket.CLOSED && this.Ephemeral && this.IsClosed) { + this.Connect(); + } + return false; + } + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendPendingRaw).call(this); + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, obj); +}, _Connection_sendPendingRaw = function _Connection_sendPendingRaw() { + while (this.PendingRaw.length > 0) { + const next = this.PendingRaw.shift(); + if (next) { + __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_sendOnWire).call(this, next); + } + } +}, _Connection_sendOnWire = function _Connection_sendOnWire(obj) { + if (this.Socket?.readyState !== WebSocket.OPEN) { + throw new Error(`Socket is not open, state is ${this.Socket?.readyState}`); + } + const json = JSON.stringify(obj); + this.Socket.send(json); + return true; +}, _Connection_maxSubscriptions_get = function _Connection_maxSubscriptions_get() { + return this.Info?.limitation?.max_subscriptions ?? 25; +}; +//# sourceMappingURL=Connection.js.map \ No newline at end of file diff --git a/packages/system/dist/Connection.js.map b/packages/system/dist/Connection.js.map new file mode 100644 index 00000000..67233092 --- /dev/null +++ b/packages/system/dist/Connection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Connection.js","sourceRoot":"","sources":["../src/Connection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.d.ts b/packages/system/dist/ConnectionStats.d.ts new file mode 100644 index 00000000..43be570b --- /dev/null +++ b/packages/system/dist/ConnectionStats.d.ts @@ -0,0 +1,30 @@ +/** + * Stats class for tracking metrics per connection + */ +export declare class ConnectionStats { + /** + * Last n records of how long between REQ->EOSE + */ + Latency: number[]; + /** + * Total number of REQ's sent on this connection + */ + Subs: number; + /** + * Count of REQ which took too long and where abandoned + */ + SubsTimeout: number; + /** + * Total number of EVENT messages received + */ + EventsReceived: number; + /** + * Total number of EVENT messages sent + */ + EventsSent: number; + /** + * Total number of times this connection was lost + */ + Disconnects: number; +} +//# sourceMappingURL=ConnectionStats.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.d.ts.map b/packages/system/dist/ConnectionStats.d.ts.map new file mode 100644 index 00000000..359e6887 --- /dev/null +++ b/packages/system/dist/ConnectionStats.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ConnectionStats.d.ts","sourceRoot":"","sources":["../src/ConnectionStats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAM;IAEvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAK;IAEjB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAK;IAExB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAK;IAE3B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAK;IAEvB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAK;CACzB"} \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.js b/packages/system/dist/ConnectionStats.js new file mode 100644 index 00000000..334cba6d --- /dev/null +++ b/packages/system/dist/ConnectionStats.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ConnectionStats = void 0; +/** + * Stats class for tracking metrics per connection + */ +class ConnectionStats { + constructor() { + /** + * Last n records of how long between REQ->EOSE + */ + this.Latency = []; + /** + * Total number of REQ's sent on this connection + */ + this.Subs = 0; + /** + * Count of REQ which took too long and where abandoned + */ + this.SubsTimeout = 0; + /** + * Total number of EVENT messages received + */ + this.EventsReceived = 0; + /** + * Total number of EVENT messages sent + */ + this.EventsSent = 0; + /** + * Total number of times this connection was lost + */ + this.Disconnects = 0; + } +} +exports.ConnectionStats = ConnectionStats; +//# sourceMappingURL=ConnectionStats.js.map \ No newline at end of file diff --git a/packages/system/dist/ConnectionStats.js.map b/packages/system/dist/ConnectionStats.js.map new file mode 100644 index 00000000..90da8778 --- /dev/null +++ b/packages/system/dist/ConnectionStats.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ConnectionStats.js","sourceRoot":"","sources":["../src/ConnectionStats.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,eAAe;IAA5B;QACE;;WAEG;QACH,YAAO,GAAa,EAAE,CAAC;QAEvB;;WAEG;QACH,SAAI,GAAW,CAAC,CAAC;QAEjB;;WAEG;QACH,gBAAW,GAAW,CAAC,CAAC;QAExB;;WAEG;QACH,mBAAc,GAAW,CAAC,CAAC;QAE3B;;WAEG;QACH,eAAU,GAAW,CAAC,CAAC;QAEvB;;WAEG;QACH,gBAAW,GAAW,CAAC,CAAC;IAC1B,CAAC;CAAA;AA9BD,0CA8BC"} \ No newline at end of file diff --git a/packages/system/dist/Const.d.ts b/packages/system/dist/Const.d.ts new file mode 100644 index 00000000..2bf82921 --- /dev/null +++ b/packages/system/dist/Const.d.ts @@ -0,0 +1,13 @@ +/** + * Websocket re-connect timeout + */ +export declare const DefaultConnectTimeout = 2000; +/** + * Hashtag regex + */ +export declare const HashtagRegex: RegExp; +/** + * How long profile cache should be considered valid for + */ +export declare const ProfileCacheExpire: number; +//# sourceMappingURL=Const.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Const.d.ts.map b/packages/system/dist/Const.d.ts.map new file mode 100644 index 00000000..222ed02a --- /dev/null +++ b/packages/system/dist/Const.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Const.d.ts","sourceRoot":"","sources":["../src/Const.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C;;GAEG;AAEH,eAAO,MAAM,YAAY,QAA4C,CAAC;AAGtE;;GAEG;AACF,eAAO,MAAM,kBAAkB,QAAsB,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/Const.js b/packages/system/dist/Const.js new file mode 100644 index 00000000..79573a84 --- /dev/null +++ b/packages/system/dist/Const.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProfileCacheExpire = exports.HashtagRegex = exports.DefaultConnectTimeout = void 0; +/** + * Websocket re-connect timeout + */ +exports.DefaultConnectTimeout = 2000; +/** + * Hashtag regex + */ +// eslint-disable-next-line no-useless-escape +exports.HashtagRegex = /(#[^\s!@#$%^&*()=+.\/,\[{\]};:'"?><]+)/g; +/** + * How long profile cache should be considered valid for + */ +exports.ProfileCacheExpire = 1000 * 60 * 60 * 6; +//# sourceMappingURL=Const.js.map \ No newline at end of file diff --git a/packages/system/dist/Const.js.map b/packages/system/dist/Const.js.map new file mode 100644 index 00000000..113dff7b --- /dev/null +++ b/packages/system/dist/Const.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Const.js","sourceRoot":"","sources":["../src/Const.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C;;GAEG;AACH,6CAA6C;AAChC,QAAA,YAAY,GAAG,yCAAyC,CAAC;AAGtE;;GAEG;AACW,QAAA,kBAAkB,GAAG,IAAK,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.d.ts b/packages/system/dist/EventBuilder.d.ts new file mode 100644 index 00000000..66b979b2 --- /dev/null +++ b/packages/system/dist/EventBuilder.d.ts @@ -0,0 +1,20 @@ +import { EventKind, HexKey, NostrEvent } from "."; +export declare class EventBuilder { + #private; + kind(k: EventKind): this; + content(c: string): this; + createdAt(n: number): this; + pubKey(k: string): this; + tag(t: Array): EventBuilder; + /** + * Extract mentions + */ + processContent(): this; + build(): NostrEvent; + /** + * Build and sign event + * @param pk Private key to sign event with + */ + buildAndSign(pk: HexKey): Promise; +} +//# sourceMappingURL=EventBuilder.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.d.ts.map b/packages/system/dist/EventBuilder.d.ts.map new file mode 100644 index 00000000..05679aaa --- /dev/null +++ b/packages/system/dist/EventBuilder.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventBuilder.d.ts","sourceRoot":"","sources":["../src/EventBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAe,UAAU,EAAE,MAAM,GAAG,CAAC;AAM/D,qBAAa,YAAY;;IAOvB,IAAI,CAAC,CAAC,EAAE,SAAS;IAKjB,OAAO,CAAC,CAAC,EAAE,MAAM;IAKjB,SAAS,CAAC,CAAC,EAAE,MAAM;IAKnB,MAAM,CAAC,CAAC,EAAE,MAAM;IAKhB,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY;IAOnC;;OAEG;IACH,cAAc;IAcd,KAAK;IAcL;;;OAGG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM;CAgC9B"} \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.js b/packages/system/dist/EventBuilder.js new file mode 100644 index 00000000..cc346664 --- /dev/null +++ b/packages/system/dist/EventBuilder.js @@ -0,0 +1,113 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _EventBuilder_instances, _EventBuilder_kind, _EventBuilder_content, _EventBuilder_createdAt, _EventBuilder_pubkey, _EventBuilder_tags, _EventBuilder_validate, _EventBuilder_replaceMention, _EventBuilder_addHashtag; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventBuilder = void 0; +const _1 = require("."); +const Const_1 = require("./Const"); +const Util_1 = require("./Util"); +const EventExt_1 = require("./EventExt"); +const NostrLink_1 = require("./NostrLink"); +class EventBuilder { + constructor() { + _EventBuilder_instances.add(this); + _EventBuilder_kind.set(this, void 0); + _EventBuilder_content.set(this, void 0); + _EventBuilder_createdAt.set(this, void 0); + _EventBuilder_pubkey.set(this, void 0); + _EventBuilder_tags.set(this, []); + } + kind(k) { + __classPrivateFieldSet(this, _EventBuilder_kind, k, "f"); + return this; + } + content(c) { + __classPrivateFieldSet(this, _EventBuilder_content, c, "f"); + return this; + } + createdAt(n) { + __classPrivateFieldSet(this, _EventBuilder_createdAt, n, "f"); + return this; + } + pubKey(k) { + __classPrivateFieldSet(this, _EventBuilder_pubkey, k, "f"); + return this; + } + tag(t) { + const duplicate = __classPrivateFieldGet(this, _EventBuilder_tags, "f").some(a => a.length === t.length && a.every((b, i) => b !== a[i])); + if (duplicate) + return this; + __classPrivateFieldGet(this, _EventBuilder_tags, "f").push(t); + return this; + } + /** + * Extract mentions + */ + processContent() { + if (__classPrivateFieldGet(this, _EventBuilder_content, "f")) { + __classPrivateFieldSet(this, _EventBuilder_content, __classPrivateFieldGet(this, _EventBuilder_content, "f").replace(/@n(pub|profile|event|ote|addr|)1[acdefghjklmnpqrstuvwxyz023456789]+/g, m => __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_replaceMention).call(this, m)), "f"); + const hashTags = [...__classPrivateFieldGet(this, _EventBuilder_content, "f").matchAll(Const_1.HashtagRegex)]; + hashTags.map(hashTag => { + __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_addHashtag).call(this, hashTag[0]); + }); + } + return this; + } + build() { + __classPrivateFieldGet(this, _EventBuilder_instances, "m", _EventBuilder_validate).call(this); + const ev = { + id: "", + pubkey: __classPrivateFieldGet(this, _EventBuilder_pubkey, "f") ?? "", + content: __classPrivateFieldGet(this, _EventBuilder_content, "f") ?? "", + kind: __classPrivateFieldGet(this, _EventBuilder_kind, "f"), + created_at: __classPrivateFieldGet(this, _EventBuilder_createdAt, "f") ?? (0, Util_1.unixNow)(), + tags: __classPrivateFieldGet(this, _EventBuilder_tags, "f"), + }; + ev.id = EventExt_1.EventExt.createId(ev); + return ev; + } + /** + * Build and sign event + * @param pk Private key to sign event with + */ + async buildAndSign(pk) { + const ev = this.pubKey((0, Util_1.getPublicKey)(pk)).build(); + await EventExt_1.EventExt.sign(ev, pk); + return ev; + } +} +exports.EventBuilder = EventBuilder; +_EventBuilder_kind = new WeakMap(), _EventBuilder_content = new WeakMap(), _EventBuilder_createdAt = new WeakMap(), _EventBuilder_pubkey = new WeakMap(), _EventBuilder_tags = new WeakMap(), _EventBuilder_instances = new WeakSet(), _EventBuilder_validate = function _EventBuilder_validate() { + if (__classPrivateFieldGet(this, _EventBuilder_kind, "f") === undefined) { + throw new Error("Kind must be set"); + } + if (__classPrivateFieldGet(this, _EventBuilder_pubkey, "f") === undefined) { + throw new Error("Pubkey must be set"); + } +}, _EventBuilder_replaceMention = function _EventBuilder_replaceMention(match) { + const npub = match.slice(1); + const link = (0, NostrLink_1.parseNostrLink)(npub); + if (link) { + if (link.type === _1.NostrPrefix.Profile || link.type === _1.NostrPrefix.PublicKey) { + this.tag(["p", link.id]); + } + return `nostr:${link.encode()}`; + } + else { + return match; + } +}, _EventBuilder_addHashtag = function _EventBuilder_addHashtag(match) { + const tag = match.slice(1); + this.tag(["t", tag.toLowerCase()]); +}; +//# sourceMappingURL=EventBuilder.js.map \ No newline at end of file diff --git a/packages/system/dist/EventBuilder.js.map b/packages/system/dist/EventBuilder.js.map new file mode 100644 index 00000000..81650cdd --- /dev/null +++ b/packages/system/dist/EventBuilder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventBuilder.js","sourceRoot":"","sources":["../src/EventBuilder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/EventExt.d.ts b/packages/system/dist/EventExt.d.ts new file mode 100644 index 00000000..055c952c --- /dev/null +++ b/packages/system/dist/EventExt.d.ts @@ -0,0 +1,42 @@ +import { EventKind, HexKey, NostrEvent, Tag } from "."; +export interface Thread { + root?: Tag; + replyTo?: Tag; + mentions: Array; + pubKeys: Array; +} +export declare abstract class EventExt { + #private; + /** + * Get the pub key of the creator of this event NIP-26 + */ + static getRootPubKey(e: NostrEvent): HexKey; + /** + * Sign this message with a private key + */ + static sign(e: NostrEvent, key: HexKey): void; + /** + * Check the signature of this message + * @returns True if valid signature + */ + static verify(e: NostrEvent): boolean; + static createId(e: NostrEvent): string; + /** + * Create a new event for a specific pubkey + */ + static forPubKey(pk: HexKey, kind: EventKind): NostrEvent; + static extractThread(ev: NostrEvent): Thread | undefined; + /** + * Encrypt the given message content + */ + static encryptData(content: string, pubkey: HexKey, privkey: HexKey): Promise; + /** + * Decrypt the content of the message + */ + static decryptData(cyphertext: string, privkey: HexKey, pubkey: HexKey): Promise; + /** + * Decrypt the content of this message in place + */ + static decryptDm(content: string, privkey: HexKey, pubkey: HexKey): Promise; +} +//# sourceMappingURL=EventExt.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventExt.d.ts.map b/packages/system/dist/EventExt.d.ts.map new file mode 100644 index 00000000..bb09e5ef --- /dev/null +++ b/packages/system/dist/EventExt.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventExt.d.ts","sourceRoot":"","sources":["../src/EventExt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC;AAIvD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,8BAAsB,QAAQ;;IAC5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM;IAS3C;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM;IAUtC;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU;IAM3B,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU;IAW7B;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS;IAY5C,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,UAAU;IAqCnC;;OAEG;WACU,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAgBzE;;OAEG;WACU,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAoB5E;;OAEG;WACU,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CASxE"} \ No newline at end of file diff --git a/packages/system/dist/EventExt.js b/packages/system/dist/EventExt.js new file mode 100644 index 00000000..eb019d83 --- /dev/null +++ b/packages/system/dist/EventExt.js @@ -0,0 +1,175 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _a, _EventExt_getDmSharedKey; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventExt = void 0; +const secp = __importStar(require("@noble/curves/secp256k1")); +const utils = __importStar(require("@noble/curves/abstract/utils")); +const _1 = require("."); +const base64_1 = __importDefault(require("@protobufjs/base64")); +const Util_1 = require("./Util"); +class EventExt { + /** + * Get the pub key of the creator of this event NIP-26 + */ + static getRootPubKey(e) { + const delegation = e.tags.find(a => a[0] === "delegation"); + if (delegation?.[1]) { + // todo: verify sig + return delegation[1]; + } + return e.pubkey; + } + /** + * Sign this message with a private key + */ + static sign(e, key) { + e.id = this.createId(e); + 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"); + } + } + /** + * Check the signature of this message + * @returns True if valid signature + */ + static verify(e) { + const id = this.createId(e); + const result = secp.schnorr.verify(e.sig, id, e.pubkey); + return result; + } + static createId(e) { + const payload = [0, e.pubkey, e.created_at, e.kind, e.tags, e.content]; + const hash = (0, Util_1.sha256)(JSON.stringify(payload)); + if (e.id !== "" && hash !== e.id) { + console.debug(payload); + throw new Error("ID doesnt match!"); + } + return hash; + } + /** + * Create a new event for a specific pubkey + */ + static forPubKey(pk, kind) { + return { + pubkey: pk, + kind: kind, + created_at: (0, Util_1.unixNow)(), + content: "", + tags: [], + id: "", + sig: "", + }; + } + static extractThread(ev) { + const isThread = ev.tags.some(a => (a[0] === "e" && a[3] !== "mention") || a[0] == "a"); + if (!isThread) { + return undefined; + } + const shouldWriteMarkers = ev.kind === _1.EventKind.TextNote; + const ret = { + mentions: [], + pubKeys: [], + }; + const eTags = ev.tags.filter(a => a[0] === "e" || a[0] === "a").map((v, i) => new _1.Tag(v, i)); + const marked = eTags.some(a => a.Marker !== undefined); + if (!marked) { + ret.root = eTags[0]; + ret.root.Marker = shouldWriteMarkers ? "root" : undefined; + if (eTags.length > 1) { + ret.replyTo = eTags[1]; + ret.replyTo.Marker = shouldWriteMarkers ? "reply" : undefined; + } + if (eTags.length > 2) { + ret.mentions = eTags.slice(2); + if (shouldWriteMarkers) { + ret.mentions.forEach(a => (a.Marker = "mention")); + } + } + } + else { + const root = eTags.find(a => a.Marker === "root"); + const reply = eTags.find(a => a.Marker === "reply"); + ret.root = root; + ret.replyTo = reply; + ret.mentions = eTags.filter(a => a.Marker === "mention"); + } + ret.pubKeys = Array.from(new Set(ev.tags.filter(a => a[0] === "p").map(a => a[1]))); + return ret; + } + /** + * Encrypt the given message content + */ + static async encryptData(content, pubkey, privkey) { + const key = await __classPrivateFieldGet(this, _a, "m", _EventExt_getDmSharedKey).call(this, pubkey, privkey); + const iv = window.crypto.getRandomValues(new Uint8Array(16)); + const data = new TextEncoder().encode(content); + const result = await window.crypto.subtle.encrypt({ + name: "AES-CBC", + iv: iv, + }, key, data); + const uData = new Uint8Array(result); + return `${base64_1.default.encode(uData, 0, result.byteLength)}?iv=${base64_1.default.encode(iv, 0, 16)}`; + } + /** + * Decrypt the content of the message + */ + static async decryptData(cyphertext, privkey, pubkey) { + const key = await __classPrivateFieldGet(this, _a, "m", _EventExt_getDmSharedKey).call(this, pubkey, privkey); + const cSplit = cyphertext.split("?iv="); + const data = new Uint8Array(base64_1.default.length(cSplit[0])); + base64_1.default.decode(cSplit[0], data, 0); + const iv = new Uint8Array(base64_1.default.length(cSplit[1])); + base64_1.default.decode(cSplit[1], iv, 0); + const result = await window.crypto.subtle.decrypt({ + name: "AES-CBC", + iv: iv, + }, key, data); + return new TextDecoder().decode(result); + } + /** + * Decrypt the content of this message in place + */ + static async decryptDm(content, privkey, pubkey) { + return await this.decryptData(content, privkey, pubkey); + } +} +exports.EventExt = EventExt; +_a = EventExt, _EventExt_getDmSharedKey = async function _EventExt_getDmSharedKey(pubkey, privkey) { + const sharedPoint = secp.secp256k1.getSharedSecret(privkey, "02" + pubkey); + const sharedX = sharedPoint.slice(1, 33); + return await window.crypto.subtle.importKey("raw", sharedX, { name: "AES-CBC" }, false, ["encrypt", "decrypt"]); +}; +//# sourceMappingURL=EventExt.js.map \ No newline at end of file diff --git a/packages/system/dist/EventExt.js.map b/packages/system/dist/EventExt.js.map new file mode 100644 index 00000000..1af29fd9 --- /dev/null +++ b/packages/system/dist/EventExt.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventExt.js","sourceRoot":"","sources":["../src/EventExt.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/EventKind.d.ts b/packages/system/dist/EventKind.d.ts new file mode 100644 index 00000000..620047bd --- /dev/null +++ b/packages/system/dist/EventKind.d.ts @@ -0,0 +1,29 @@ +declare enum EventKind { + Unknown = -1, + SetMetadata = 0, + TextNote = 1, + RecommendServer = 2, + ContactList = 3, + DirectMessage = 4, + Deletion = 5, + Repost = 6, + Reaction = 7, + BadgeAward = 8, + SnortSubscriptions = 1000, + Polls = 6969, + FileHeader = 1063, + Relays = 10002, + Ephemeral = 20000, + Auth = 22242, + PubkeyLists = 30000, + NoteLists = 30001, + TagLists = 30002, + Badge = 30009, + ProfileBadges = 30008, + ZapstrTrack = 31337, + ZapRequest = 9734, + ZapReceipt = 9735, + HttpAuthentication = 27235 +} +export default EventKind; +//# sourceMappingURL=EventKind.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventKind.d.ts.map b/packages/system/dist/EventKind.d.ts.map new file mode 100644 index 00000000..2cf2c3fd --- /dev/null +++ b/packages/system/dist/EventKind.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventKind.d.ts","sourceRoot":"","sources":["../src/EventKind.ts"],"names":[],"mappings":"AAAA,aAAK,SAAS;IACZ,OAAO,KAAK;IACZ,WAAW,IAAI;IACf,QAAQ,IAAI;IACZ,eAAe,IAAI;IACnB,WAAW,IAAI;IACf,aAAa,IAAI;IACjB,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,UAAU,IAAI;IACd,kBAAkB,OAAO;IACzB,KAAK,OAAO;IACZ,UAAU,OAAO;IACjB,MAAM,QAAQ;IACd,SAAS,QAAS;IAClB,IAAI,QAAQ;IACZ,WAAW,QAAQ;IACnB,SAAS,QAAQ;IACjB,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,aAAa,QAAQ;IACrB,WAAW,QAAQ;IACnB,UAAU,OAAO;IACjB,UAAU,OAAO;IACjB,kBAAkB,QAAQ;CAC3B;AAED,eAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventKind.js b/packages/system/dist/EventKind.js new file mode 100644 index 00000000..d4a5c88a --- /dev/null +++ b/packages/system/dist/EventKind.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var EventKind; +(function (EventKind) { + EventKind[EventKind["Unknown"] = -1] = "Unknown"; + EventKind[EventKind["SetMetadata"] = 0] = "SetMetadata"; + EventKind[EventKind["TextNote"] = 1] = "TextNote"; + EventKind[EventKind["RecommendServer"] = 2] = "RecommendServer"; + EventKind[EventKind["ContactList"] = 3] = "ContactList"; + EventKind[EventKind["DirectMessage"] = 4] = "DirectMessage"; + EventKind[EventKind["Deletion"] = 5] = "Deletion"; + EventKind[EventKind["Repost"] = 6] = "Repost"; + EventKind[EventKind["Reaction"] = 7] = "Reaction"; + EventKind[EventKind["BadgeAward"] = 8] = "BadgeAward"; + EventKind[EventKind["SnortSubscriptions"] = 1000] = "SnortSubscriptions"; + EventKind[EventKind["Polls"] = 6969] = "Polls"; + EventKind[EventKind["FileHeader"] = 1063] = "FileHeader"; + EventKind[EventKind["Relays"] = 10002] = "Relays"; + EventKind[EventKind["Ephemeral"] = 20000] = "Ephemeral"; + EventKind[EventKind["Auth"] = 22242] = "Auth"; + EventKind[EventKind["PubkeyLists"] = 30000] = "PubkeyLists"; + EventKind[EventKind["NoteLists"] = 30001] = "NoteLists"; + EventKind[EventKind["TagLists"] = 30002] = "TagLists"; + EventKind[EventKind["Badge"] = 30009] = "Badge"; + EventKind[EventKind["ProfileBadges"] = 30008] = "ProfileBadges"; + EventKind[EventKind["ZapstrTrack"] = 31337] = "ZapstrTrack"; + EventKind[EventKind["ZapRequest"] = 9734] = "ZapRequest"; + EventKind[EventKind["ZapReceipt"] = 9735] = "ZapReceipt"; + EventKind[EventKind["HttpAuthentication"] = 27235] = "HttpAuthentication"; +})(EventKind || (EventKind = {})); +exports.default = EventKind; +//# sourceMappingURL=EventKind.js.map \ No newline at end of file diff --git a/packages/system/dist/EventKind.js.map b/packages/system/dist/EventKind.js.map new file mode 100644 index 00000000..4cdf3259 --- /dev/null +++ b/packages/system/dist/EventKind.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventKind.js","sourceRoot":"","sources":["../src/EventKind.ts"],"names":[],"mappings":";;AAAA,IAAK,SA0BJ;AA1BD,WAAK,SAAS;IACZ,gDAAY,CAAA;IACZ,uDAAe,CAAA;IACf,iDAAY,CAAA;IACZ,+DAAmB,CAAA;IACnB,uDAAe,CAAA;IACf,2DAAiB,CAAA;IACjB,iDAAY,CAAA;IACZ,6CAAU,CAAA;IACV,iDAAY,CAAA;IACZ,qDAAc,CAAA;IACd,wEAAyB,CAAA;IACzB,8CAAY,CAAA;IACZ,wDAAiB,CAAA;IACjB,iDAAc,CAAA;IACd,uDAAkB,CAAA;IAClB,6CAAY,CAAA;IACZ,2DAAmB,CAAA;IACnB,uDAAiB,CAAA;IACjB,qDAAgB,CAAA;IAChB,+CAAa,CAAA;IACb,+DAAqB,CAAA;IACrB,2DAAmB,CAAA;IACnB,wDAAiB,CAAA;IACjB,wDAAiB,CAAA;IACjB,yEAA0B,CAAA;AAC5B,CAAC,EA1BI,SAAS,KAAT,SAAS,QA0Bb;AAED,kBAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.d.ts b/packages/system/dist/EventPublisher.d.ts new file mode 100644 index 00000000..d121228e --- /dev/null +++ b/packages/system/dist/EventPublisher.d.ts @@ -0,0 +1,66 @@ +import { FullRelaySettings, HexKey, Lists, NostrEvent, RelaySettings, SystemInterface, TaggedRawEvent, u256, UserMetadata } from "."; +import { EventBuilder } from "./EventBuilder"; +export type EventBuilderHook = (ev: EventBuilder) => EventBuilder; +declare global { + interface Window { + nostr?: { + getPublicKey: () => Promise; + signEvent: (event: T) => Promise; + getRelays?: () => Promise>; + nip04?: { + encrypt?: (pubkey: HexKey, plaintext: string) => Promise; + decrypt?: (pubkey: HexKey, ciphertext: string) => Promise; + }; + }; + } +} +export declare class EventPublisher { + #private; + constructor(system: SystemInterface, pubKey: string, privKey?: string); + nip4Encrypt(content: string, key: HexKey): Promise; + nip4Decrypt(content: string, otherKey: HexKey): Promise; + nip42Auth(challenge: string, relay: string): Promise; + broadcast(ev: NostrEvent): void; + /** + * Write event to all given relays. + */ + broadcastAll(ev: NostrEvent, relays: string[]): void; + muted(keys: HexKey[], priv: HexKey[]): Promise; + noteList(notes: u256[], list: Lists): Promise; + tags(tags: string[]): Promise; + metadata(obj: UserMetadata): Promise; + /** + * Create a basic text note + */ + note(msg: string, fnExtra?: EventBuilderHook): Promise; + /** + * Create a zap request event for a given target event/profile + * @param amount Millisats amout! + * @param author Author pubkey to tag in the zap + * @param note Note Id to tag in the zap + * @param msg Custom message to be included in the zap + */ + zap(amount: number, author: HexKey, relays: Array, note?: HexKey, msg?: string, fnExtra?: EventBuilderHook): Promise; + /** + * Reply to a note + */ + reply(replyTo: TaggedRawEvent, msg: string, fnExtra?: EventBuilderHook): Promise; + react(evRef: NostrEvent, content?: string): Promise; + relayList(relays: Array | Record): Promise; + contactList(follows: Array, relays: Record): Promise; + /** + * Delete an event (NIP-09) + */ + delete(id: u256): Promise; + /** + * Repost a note (NIP-18) + */ + repost(note: NostrEvent): Promise; + decryptDm(note: NostrEvent): Promise; + sendDm(content: string, to: HexKey): Promise; + generic(fnHook: EventBuilderHook): Promise; +} +//# sourceMappingURL=EventPublisher.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.d.ts.map b/packages/system/dist/EventPublisher.d.ts.map new file mode 100644 index 00000000..10509c14 --- /dev/null +++ b/packages/system/dist/EventPublisher.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"EventPublisher.d.ts","sourceRoot":"","sources":["../src/EventPublisher.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.js b/packages/system/dist/EventPublisher.js new file mode 100644 index 00000000..e392994a --- /dev/null +++ b/packages/system/dist/EventPublisher.js @@ -0,0 +1,295 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _EventPublisher_instances, _EventPublisher_system, _EventPublisher_pubKey, _EventPublisher_privateKey, _EventPublisher_hasNip07_get, _EventPublisher_eb, _EventPublisher_sign; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EventPublisher = void 0; +const secp = __importStar(require("@noble/curves/secp256k1")); +const utils = __importStar(require("@noble/curves/abstract/utils")); +const _1 = require("."); +const Util_1 = require("./Util"); +const EventBuilder_1 = require("./EventBuilder"); +const EventExt_1 = require("./EventExt"); +const WorkQueue_1 = require("./WorkQueue"); +const Nip7Queue = []; +(0, WorkQueue_1.processWorkQueue)(Nip7Queue); +class EventPublisher { + constructor(system, pubKey, privKey) { + _EventPublisher_instances.add(this); + _EventPublisher_system.set(this, void 0); + _EventPublisher_pubKey.set(this, void 0); + _EventPublisher_privateKey.set(this, void 0); + __classPrivateFieldSet(this, _EventPublisher_system, system, "f"); + if (privKey) { + __classPrivateFieldSet(this, _EventPublisher_privateKey, privKey, "f"); + __classPrivateFieldSet(this, _EventPublisher_pubKey, utils.bytesToHex(secp.schnorr.getPublicKey(privKey)), "f"); + } + else { + __classPrivateFieldSet(this, _EventPublisher_pubKey, pubKey, "f"); + } + } + async nip4Encrypt(content, key) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + const nip7PubKey = await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).getPublicKey()); + if (nip7PubKey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + throw new Error("Can't encrypt content, NIP-07 pubkey does not match"); + } + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr?.nip04?.encrypt).call(window.nostr?.nip04, key, content)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await EventExt_1.EventExt.encryptData(content, key, __classPrivateFieldGet(this, _EventPublisher_privateKey, "f")); + } + else { + throw new Error("Can't encrypt content, no private keys available"); + } + } + async nip4Decrypt(content, otherKey) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f") && window.nostr?.nip04?.decrypt) { + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr?.nip04?.decrypt).call(window.nostr?.nip04, otherKey, content)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await EventExt_1.EventExt.decryptDm(content, __classPrivateFieldGet(this, _EventPublisher_privateKey, "f"), otherKey); + } + else { + throw new Error("Can't decrypt content, no private keys available"); + } + } + async nip42Auth(challenge, relay) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Auth); + eb.tag(["relay", relay]); + eb.tag(["challenge", challenge]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + broadcast(ev) { + console.debug(ev); + __classPrivateFieldGet(this, _EventPublisher_system, "f").BroadcastEvent(ev); + } + /** + * Write event to all given relays. + */ + broadcastAll(ev, relays) { + for (const k of relays) { + __classPrivateFieldGet(this, _EventPublisher_system, "f").WriteOnceToRelay(k, ev); + } + } + async muted(keys, priv) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.PubkeyLists); + eb.tag(["d", _1.Lists.Muted]); + keys.forEach(p => { + eb.tag(["p", p]); + }); + if (priv.length > 0) { + const ps = priv.map(p => ["p", p]); + const plaintext = JSON.stringify(ps); + eb.content(await this.nip4Encrypt(plaintext, __classPrivateFieldGet(this, _EventPublisher_pubKey, "f"))); + } + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async noteList(notes, list) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.NoteLists); + eb.tag(["d", list]); + notes.forEach(n => { + eb.tag(["e", n]); + }); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async tags(tags) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TagLists); + eb.tag(["d", _1.Lists.Followed]); + tags.forEach(t => { + eb.tag(["t", t]); + }); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async metadata(obj) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.SetMetadata); + eb.content(JSON.stringify(obj)); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Create a basic text note + */ + async note(msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TextNote); + eb.content(msg); + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Create a zap request event for a given target event/profile + * @param amount Millisats amout! + * @param author Author pubkey to tag in the zap + * @param note Note Id to tag in the zap + * @param msg Custom message to be included in the zap + */ + async zap(amount, author, relays, note, msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.ZapRequest); + eb.content(msg ?? ""); + if (note) { + eb.tag(["e", note]); + } + eb.tag(["p", author]); + eb.tag(["relays", ...relays.map(a => a.trim())]); + eb.tag(["amount", amount.toString()]); + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Reply to a note + */ + async reply(replyTo, msg, fnExtra) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.TextNote); + eb.content(msg); + const thread = EventExt_1.EventExt.extractThread(replyTo); + if (thread) { + if (thread.root || thread.replyTo) { + eb.tag(["e", thread.root?.Event ?? thread.replyTo?.Event ?? "", "", "root"]); + } + eb.tag(["e", replyTo.id, replyTo.relays?.[0] ?? "", "reply"]); + eb.tag(["p", replyTo.pubkey]); + for (const pk of thread.pubKeys) { + if (pk === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + continue; + } + eb.tag(["p", pk]); + } + } + else { + eb.tag(["e", replyTo.id, "", "reply"]); + // dont tag self in replies + if (replyTo.pubkey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + eb.tag(["p", replyTo.pubkey]); + } + } + eb.processContent(); + fnExtra?.(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async react(evRef, content = "+") { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Reaction); + eb.content(content); + eb.tag(["e", evRef.id]); + eb.tag(["p", evRef.pubkey]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async relayList(relays) { + if (!Array.isArray(relays)) { + relays = Object.entries(relays).map(([k, v]) => ({ + url: k, + settings: v, + })); + } + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.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"); + } + eb.tag(rTag); + } + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async contactList(follows, relays) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.ContactList); + eb.content(JSON.stringify(relays)); + const temp = new Set(follows.filter(a => a.length === 64).map(a => a.toLowerCase())); + temp.forEach(a => eb.tag(["p", a])); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Delete an event (NIP-09) + */ + async delete(id) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Deletion); + eb.tag(["e", id]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + /** + * Repost a note (NIP-18) + */ + async repost(note) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.Repost); + eb.tag(["e", note.id, ""]); + eb.tag(["p", note.pubkey]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async decryptDm(note) { + if (note.pubkey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f") && !note.tags.some(a => a[1] === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f"))) { + throw new Error("Can't decrypt, DM does not belong to this user"); + } + const otherPubKey = note.pubkey === __classPrivateFieldGet(this, _EventPublisher_pubKey, "f") ? (0, Util_1.unwrap)(note.tags.find(a => a[0] === "p")?.[1]) : note.pubkey; + return await this.nip4Decrypt(note.content, otherPubKey); + } + async sendDm(content, to) { + const eb = __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_eb).call(this, _1.EventKind.DirectMessage); + eb.content(await this.nip4Encrypt(content, to)); + eb.tag(["p", to]); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } + async generic(fnHook) { + const eb = new EventBuilder_1.EventBuilder(); + eb.pubKey(__classPrivateFieldGet(this, _EventPublisher_pubKey, "f")); + fnHook(eb); + return await __classPrivateFieldGet(this, _EventPublisher_instances, "m", _EventPublisher_sign).call(this, eb); + } +} +exports.EventPublisher = EventPublisher; +_EventPublisher_system = new WeakMap(), _EventPublisher_pubKey = new WeakMap(), _EventPublisher_privateKey = new WeakMap(), _EventPublisher_instances = new WeakSet(), _EventPublisher_hasNip07_get = function _EventPublisher_hasNip07_get() { + return "nostr" in window; +}, _EventPublisher_eb = function _EventPublisher_eb(k) { + const eb = new EventBuilder_1.EventBuilder(); + return eb.pubKey(__classPrivateFieldGet(this, _EventPublisher_pubKey, "f")).kind(k); +}, _EventPublisher_sign = async function _EventPublisher_sign(eb) { + if (__classPrivateFieldGet(this, _EventPublisher_instances, "a", _EventPublisher_hasNip07_get) && !__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + const nip7PubKey = await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).getPublicKey()); + if (nip7PubKey !== __classPrivateFieldGet(this, _EventPublisher_pubKey, "f")) { + throw new Error("Can't sign event, NIP-07 pubkey does not match"); + } + const ev = eb.build(); + return await (0, WorkQueue_1.barrierQueue)(Nip7Queue, () => (0, Util_1.unwrap)(window.nostr).signEvent(ev)); + } + else if (__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")) { + return await eb.buildAndSign(__classPrivateFieldGet(this, _EventPublisher_privateKey, "f")); + } + else { + throw new Error("Can't sign event, no private keys available"); + } +}; +//# sourceMappingURL=EventPublisher.js.map \ No newline at end of file diff --git a/packages/system/dist/EventPublisher.js.map b/packages/system/dist/EventPublisher.js.map new file mode 100644 index 00000000..1f95e3ad --- /dev/null +++ b/packages/system/dist/EventPublisher.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EventPublisher.js","sourceRoot":"","sources":["../src/EventPublisher.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.d.ts b/packages/system/dist/ExternalStore.d.ts new file mode 100644 index 00000000..2c483f6d --- /dev/null +++ b/packages/system/dist/ExternalStore.d.ts @@ -0,0 +1,13 @@ +type HookFn = (e?: TSnapshot) => void; +/** + * Simple React hookable store with manual change notifications + */ +export default abstract class ExternalStore { + #private; + hook(fn: HookFn): () => void; + snapshot(): Readonly; + protected notifyChange(sn?: TSnapshot): void; + abstract takeSnapshot(): TSnapshot; +} +export {}; +//# sourceMappingURL=ExternalStore.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.d.ts.map b/packages/system/dist/ExternalStore.d.ts.map new file mode 100644 index 00000000..9c439d8d --- /dev/null +++ b/packages/system/dist/ExternalStore.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ExternalStore.d.ts","sourceRoot":"","sources":["../src/ExternalStore.ts"],"names":[],"mappings":"AAAA,KAAK,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;AAMjD;;GAEG;AACH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa,CAAC,SAAS;;IAKnD,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;IAY1B,QAAQ;IAQR,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,SAAS;IAKrC,QAAQ,CAAC,YAAY,IAAI,SAAS;CACnC"} \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.js b/packages/system/dist/ExternalStore.js new file mode 100644 index 00000000..47daafe4 --- /dev/null +++ b/packages/system/dist/ExternalStore.js @@ -0,0 +1,49 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _ExternalStore_hooks, _ExternalStore_snapshot, _ExternalStore_changed; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Simple React hookable store with manual change notifications + */ +class ExternalStore { + constructor() { + _ExternalStore_hooks.set(this, []); + _ExternalStore_snapshot.set(this, {}); + _ExternalStore_changed.set(this, true); + } + hook(fn) { + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").push({ + fn, + }); + return () => { + const idx = __classPrivateFieldGet(this, _ExternalStore_hooks, "f").findIndex(a => a.fn === fn); + if (idx >= 0) { + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").splice(idx, 1); + } + }; + } + snapshot() { + if (__classPrivateFieldGet(this, _ExternalStore_changed, "f")) { + __classPrivateFieldSet(this, _ExternalStore_snapshot, this.takeSnapshot(), "f"); + __classPrivateFieldSet(this, _ExternalStore_changed, false, "f"); + } + return __classPrivateFieldGet(this, _ExternalStore_snapshot, "f"); + } + notifyChange(sn) { + __classPrivateFieldSet(this, _ExternalStore_changed, true, "f"); + __classPrivateFieldGet(this, _ExternalStore_hooks, "f").forEach(h => h.fn(sn)); + } +} +exports.default = ExternalStore; +_ExternalStore_hooks = new WeakMap(), _ExternalStore_snapshot = new WeakMap(), _ExternalStore_changed = new WeakMap(); +//# sourceMappingURL=ExternalStore.js.map \ No newline at end of file diff --git a/packages/system/dist/ExternalStore.js.map b/packages/system/dist/ExternalStore.js.map new file mode 100644 index 00000000..483f5f23 --- /dev/null +++ b/packages/system/dist/ExternalStore.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ExternalStore.js","sourceRoot":"","sources":["../src/ExternalStore.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAMA;;GAEG;AACH,MAA8B,aAAa;IAA3C;QACE,+BAAuC,EAAE,EAAC;QAC1C,kCAAiC,EAAyB,EAAC;QAC3D,iCAAW,IAAI,EAAC;IA4BlB,CAAC;IA1BC,IAAI,CAAC,EAAqB;QACxB,uBAAA,IAAI,4BAAO,CAAC,IAAI,CAAC;YACf,EAAE;SACH,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,uBAAA,IAAI,4BAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACpD,IAAI,GAAG,IAAI,CAAC,EAAE;gBACZ,uBAAA,IAAI,4BAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;aAC5B;QACH,CAAC,CAAC;IACJ,CAAC;IAED,QAAQ;QACN,IAAI,uBAAA,IAAI,8BAAS,EAAE;YACjB,uBAAA,IAAI,2BAAa,IAAI,CAAC,YAAY,EAAE,MAAA,CAAC;YACrC,uBAAA,IAAI,0BAAY,KAAK,MAAA,CAAC;SACvB;QACD,OAAO,uBAAA,IAAI,+BAAU,CAAC;IACxB,CAAC;IAES,YAAY,CAAC,EAAc;QACnC,uBAAA,IAAI,0BAAY,IAAI,MAAA,CAAC;QACrB,uBAAA,IAAI,4BAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;CAGF;AA/BD,gCA+BC"} \ No newline at end of file diff --git a/packages/system/dist/GossipModel.d.ts b/packages/system/dist/GossipModel.d.ts new file mode 100644 index 00000000..a4e1c8b8 --- /dev/null +++ b/packages/system/dist/GossipModel.d.ts @@ -0,0 +1,20 @@ +import { FullRelaySettings, ReqFilter } from "."; +export interface RelayTaggedFilter { + relay: string; + filter: ReqFilter; +} +export interface RelayTaggedFilters { + relay: string; + filters: Array; +} +export interface RelayCache { + get(pubkey?: string): Array | undefined; +} +export declare function splitAllByWriteRelays(cache: RelayCache, filters: Array): RelayTaggedFilters[]; +/** + * Split filters by authors + * @param filter + * @returns + */ +export declare function splitByWriteRelays(cache: RelayCache, filter: ReqFilter): Array; +//# sourceMappingURL=GossipModel.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/GossipModel.d.ts.map b/packages/system/dist/GossipModel.d.ts.map new file mode 100644 index 00000000..3328b5e2 --- /dev/null +++ b/packages/system/dist/GossipModel.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"GossipModel.d.ts","sourceRoot":"","sources":["../src/GossipModel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAMjD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;CAC5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,wBAqBjF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAoEjG"} \ No newline at end of file diff --git a/packages/system/dist/GossipModel.js b/packages/system/dist/GossipModel.js new file mode 100644 index 00000000..1668805e --- /dev/null +++ b/packages/system/dist/GossipModel.js @@ -0,0 +1,102 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.splitByWriteRelays = exports.splitAllByWriteRelays = void 0; +const Util_1 = require("./Util"); +const debug_1 = __importDefault(require("debug")); +const PickNRelays = 2; +function splitAllByWriteRelays(cache, filters) { + const allSplit = filters + .map(a => splitByWriteRelays(cache, a)) + .reduce((acc, v) => { + for (const vn of v) { + const existing = acc.get(vn.relay); + if (existing) { + existing.push(vn.filter); + } + else { + acc.set(vn.relay, [vn.filter]); + } + } + return acc; + }, new Map()); + return [...allSplit.entries()].map(([k, v]) => { + return { + relay: k, + filters: v, + }; + }); +} +exports.splitAllByWriteRelays = splitAllByWriteRelays; +/** + * Split filters by authors + * @param filter + * @returns + */ +function splitByWriteRelays(cache, filter) { + if ((filter.authors?.length ?? 0) === 0) + return [ + { + relay: "", + filter, + }, + ]; + const allRelays = (0, Util_1.unwrap)(filter.authors).map(a => { + return { + key: a, + relays: cache.get(a)?.filter(a => a.settings.write), + }; + }); + const missing = allRelays.filter(a => a.relays === undefined); + const hasRelays = allRelays.filter(a => a.relays !== undefined); + const relayUserMap = hasRelays.reduce((acc, v) => { + for (const r of (0, Util_1.unwrap)(v.relays)) { + if (!acc.has(r.url)) { + acc.set(r.url, new Set([v.key])); + } + else { + (0, Util_1.unwrap)(acc.get(r.url)).add(v.key); + } + } + return acc; + }, new Map()); + // selection algo will just pick relays with the most users + const topRelays = [...relayUserMap.entries()].sort(([, v], [, v1]) => v1.size - v.size); + // - count keys per relay + // - pick n top relays + // - map keys per relay (for subscription filter) + const userPickedRelays = (0, Util_1.unwrap)(filter.authors).map(k => { + // pick top 3 relays for this key + const relaysForKey = topRelays + .filter(([, v]) => v.has(k)) + .slice(0, PickNRelays) + .map(([k]) => k); + return { k, relaysForKey }; + }); + const pickedRelays = new Set(userPickedRelays.map(a => a.relaysForKey).flat()); + const picked = [...pickedRelays].map(a => { + const keysOnPickedRelay = new Set(userPickedRelays.filter(b => b.relaysForKey.includes(a)).map(b => b.k)); + return { + relay: a, + filter: { + ...filter, + authors: [...keysOnPickedRelay], + }, + }; + }); + if (missing.length > 0) { + picked.push({ + relay: "", + filter: { + ...filter, + authors: missing.map(a => a.key), + }, + }); + } + (0, debug_1.default)("GOSSIP")("Picked %o", picked); + return picked; +} +exports.splitByWriteRelays = splitByWriteRelays; +//# sourceMappingURL=GossipModel.js.map \ No newline at end of file diff --git a/packages/system/dist/GossipModel.js.map b/packages/system/dist/GossipModel.js.map new file mode 100644 index 00000000..0bddddb1 --- /dev/null +++ b/packages/system/dist/GossipModel.js.map @@ -0,0 +1 @@ +{"version":3,"file":"GossipModel.js","sourceRoot":"","sources":["../src/GossipModel.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Links.d.ts b/packages/system/dist/Links.d.ts new file mode 100644 index 00000000..bd3ed4c0 --- /dev/null +++ b/packages/system/dist/Links.d.ts @@ -0,0 +1,24 @@ +import { HexKey } from "./Nostr"; +export declare enum NostrPrefix { + PublicKey = "npub", + PrivateKey = "nsec", + Note = "note", + Profile = "nprofile", + Event = "nevent", + Relay = "nrelay", + Address = "naddr" +} +export declare enum TLVEntryType { + Special = 0, + Relay = 1, + Author = 2, + Kind = 3 +} +export interface TLVEntry { + type: TLVEntryType; + length: number; + value: string | HexKey | number; +} +export declare function encodeTLV(prefix: NostrPrefix, id: string, relays?: string[], kind?: number, author?: string): string; +export declare function decodeTLV(str: string): TLVEntry[]; +//# sourceMappingURL=Links.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Links.d.ts.map b/packages/system/dist/Links.d.ts.map new file mode 100644 index 00000000..a7158f31 --- /dev/null +++ b/packages/system/dist/Links.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Links.d.ts","sourceRoot":"","sources":["../src/Links.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,oBAAY,WAAW;IACrB,SAAS,SAAS;IAClB,UAAU,SAAS;IACnB,IAAI,SAAS;IAGb,OAAO,aAAa;IACpB,KAAK,WAAW;IAChB,KAAK,WAAW;IAChB,OAAO,UAAU;CAClB;AAED,oBAAY,YAAY;IACtB,OAAO,IAAI;IACX,KAAK,IAAI;IACT,MAAM,IAAI;IACV,IAAI,IAAI;CACT;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CACjC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,UAiB3G;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,cAkBpC"} \ No newline at end of file diff --git a/packages/system/dist/Links.js b/packages/system/dist/Links.js new file mode 100644 index 00000000..727ae9de --- /dev/null +++ b/packages/system/dist/Links.js @@ -0,0 +1,102 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decodeTLV = exports.encodeTLV = exports.TLVEntryType = exports.NostrPrefix = void 0; +const utils = __importStar(require("@noble/curves/abstract/utils")); +const bech32_1 = require("bech32"); +var NostrPrefix; +(function (NostrPrefix) { + NostrPrefix["PublicKey"] = "npub"; + NostrPrefix["PrivateKey"] = "nsec"; + NostrPrefix["Note"] = "note"; + // TLV prefixes + NostrPrefix["Profile"] = "nprofile"; + NostrPrefix["Event"] = "nevent"; + NostrPrefix["Relay"] = "nrelay"; + NostrPrefix["Address"] = "naddr"; +})(NostrPrefix = exports.NostrPrefix || (exports.NostrPrefix = {})); +var TLVEntryType; +(function (TLVEntryType) { + TLVEntryType[TLVEntryType["Special"] = 0] = "Special"; + TLVEntryType[TLVEntryType["Relay"] = 1] = "Relay"; + TLVEntryType[TLVEntryType["Author"] = 2] = "Author"; + TLVEntryType[TLVEntryType["Kind"] = 3] = "Kind"; +})(TLVEntryType = exports.TLVEntryType || (exports.TLVEntryType = {})); +function encodeTLV(prefix, id, relays, kind, author) { + const enc = new TextEncoder(); + const buf = prefix === NostrPrefix.Address ? enc.encode(id) : utils.hexToBytes(id); + const tl0 = [0, buf.length, ...buf]; + const tl1 = relays + ?.map(a => { + const data = enc.encode(a); + return [1, data.length, ...data]; + }) + .flat() ?? []; + const tl2 = author ? [2, 32, ...utils.hexToBytes(author)] : []; + const tl3 = kind ? [3, 4, ...new Uint8Array(new Uint32Array([kind]).buffer).reverse()] : []; + return bech32_1.bech32.encode(prefix, bech32_1.bech32.toWords([...tl0, ...tl1, ...tl2, ...tl3]), 1000); +} +exports.encodeTLV = encodeTLV; +function decodeTLV(str) { + const decoded = bech32_1.bech32.decode(str, 1000); + const data = bech32_1.bech32.fromWords(decoded.words); + const entries = []; + let x = 0; + while (x < data.length) { + const t = data[x]; + const l = data[x + 1]; + const v = data.slice(x + 2, x + 2 + l); + entries.push({ + type: t, + length: l, + value: decodeTLVEntry(t, decoded.prefix, new Uint8Array(v)), + }); + x += 2 + l; + } + return entries; +} +exports.decodeTLV = decodeTLV; +function decodeTLVEntry(type, prefix, data) { + switch (type) { + case TLVEntryType.Special: { + if (prefix === NostrPrefix.Address) { + return new TextDecoder("ASCII").decode(data); + } + else { + return utils.bytesToHex(data); + } + } + case TLVEntryType.Author: { + return utils.bytesToHex(data); + } + case TLVEntryType.Kind: { + return new Uint32Array(new Uint8Array(data.reverse()).buffer)[0]; + } + case TLVEntryType.Relay: { + return new TextDecoder("ASCII").decode(data); + } + } +} +//# sourceMappingURL=Links.js.map \ No newline at end of file diff --git a/packages/system/dist/Links.js.map b/packages/system/dist/Links.js.map new file mode 100644 index 00000000..277242a7 --- /dev/null +++ b/packages/system/dist/Links.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Links.js","sourceRoot":"","sources":["../src/Links.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Nips.d.ts b/packages/system/dist/Nips.d.ts new file mode 100644 index 00000000..e3486652 --- /dev/null +++ b/packages/system/dist/Nips.d.ts @@ -0,0 +1,4 @@ +export declare enum Nips { + Search = 50 +} +//# sourceMappingURL=Nips.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Nips.d.ts.map b/packages/system/dist/Nips.d.ts.map new file mode 100644 index 00000000..42dcd779 --- /dev/null +++ b/packages/system/dist/Nips.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Nips.d.ts","sourceRoot":"","sources":["../src/Nips.ts"],"names":[],"mappings":"AAAA,oBAAY,IAAI;IACd,MAAM,KAAK;CACZ"} \ No newline at end of file diff --git a/packages/system/dist/Nips.js b/packages/system/dist/Nips.js new file mode 100644 index 00000000..80b98f7c --- /dev/null +++ b/packages/system/dist/Nips.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Nips = void 0; +var Nips; +(function (Nips) { + Nips[Nips["Search"] = 50] = "Search"; +})(Nips = exports.Nips || (exports.Nips = {})); +//# sourceMappingURL=Nips.js.map \ No newline at end of file diff --git a/packages/system/dist/Nips.js.map b/packages/system/dist/Nips.js.map new file mode 100644 index 00000000..b5276f39 --- /dev/null +++ b/packages/system/dist/Nips.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Nips.js","sourceRoot":"","sources":["../src/Nips.ts"],"names":[],"mappings":";;;AAAA,IAAY,IAEX;AAFD,WAAY,IAAI;IACd,oCAAW,CAAA;AACb,CAAC,EAFW,IAAI,GAAJ,YAAI,KAAJ,YAAI,QAEf"} \ No newline at end of file diff --git a/packages/system/dist/Nostr.d.ts b/packages/system/dist/Nostr.d.ts new file mode 100644 index 00000000..040af7b8 --- /dev/null +++ b/packages/system/dist/Nostr.d.ts @@ -0,0 +1,75 @@ +import { RelaySettings } from "./Connection"; +export interface NostrEvent { + id: u256; + pubkey: HexKey; + created_at: number; + kind: number; + tags: Array>; + content: string; + sig: string; +} +export interface TaggedRawEvent extends NostrEvent { + /** + * A list of relays this event was seen on + */ + relays: string[]; +} +/** + * Basic raw key as hex + */ +export type HexKey = string; +/** + * Optional HexKey + */ +export type MaybeHexKey = HexKey | undefined; +/** + * A 256bit hex id + */ +export type u256 = string; +export type ReqCommand = [cmd: "REQ", id: string, ...filters: Array]; +/** + * Raw REQ filter object + */ +export interface ReqFilter { + ids?: u256[]; + authors?: u256[]; + kinds?: number[]; + "#e"?: u256[]; + "#p"?: u256[]; + "#t"?: string[]; + "#d"?: string[]; + "#r"?: string[]; + search?: string; + since?: number; + until?: number; + limit?: number; +} +/** + * Medatadata event content + */ +export type UserMetadata = { + name?: string; + display_name?: string; + about?: string; + picture?: string; + website?: string; + banner?: string; + nip05?: string; + lud06?: string; + lud16?: string; +}; +/** + * NIP-51 list types + */ +export declare enum Lists { + Muted = "mute", + Pinned = "pin", + Bookmarked = "bookmark", + Followed = "follow", + Badges = "profile_badges" +} +export interface FullRelaySettings { + url: string; + settings: RelaySettings; +} +//# sourceMappingURL=Nostr.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Nostr.d.ts.map b/packages/system/dist/Nostr.d.ts.map new file mode 100644 index 00000000..6e003def --- /dev/null +++ b/packages/system/dist/Nostr.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Nostr.d.ts","sourceRoot":"","sources":["../src/Nostr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;IACb,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,oBAAY,KAAK;IACf,KAAK,SAAS;IACd,MAAM,QAAQ;IACd,UAAU,aAAa;IACvB,QAAQ,WAAW;IACnB,MAAM,mBAAmB;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,aAAa,CAAC;CACzB"} \ No newline at end of file diff --git a/packages/system/dist/Nostr.js b/packages/system/dist/Nostr.js new file mode 100644 index 00000000..5c2cad16 --- /dev/null +++ b/packages/system/dist/Nostr.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Lists = void 0; +/** + * NIP-51 list types + */ +var Lists; +(function (Lists) { + Lists["Muted"] = "mute"; + Lists["Pinned"] = "pin"; + Lists["Bookmarked"] = "bookmark"; + Lists["Followed"] = "follow"; + Lists["Badges"] = "profile_badges"; +})(Lists = exports.Lists || (exports.Lists = {})); +//# sourceMappingURL=Nostr.js.map \ No newline at end of file diff --git a/packages/system/dist/Nostr.js.map b/packages/system/dist/Nostr.js.map new file mode 100644 index 00000000..1100ff69 --- /dev/null +++ b/packages/system/dist/Nostr.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Nostr.js","sourceRoot":"","sources":["../src/Nostr.ts"],"names":[],"mappings":";;;AAqEA;;GAEG;AACH,IAAY,KAMX;AAND,WAAY,KAAK;IACf,uBAAc,CAAA;IACd,uBAAc,CAAA;IACd,gCAAuB,CAAA;IACvB,4BAAmB,CAAA;IACnB,kCAAyB,CAAA;AAC3B,CAAC,EANW,KAAK,GAAL,aAAK,KAAL,aAAK,QAMhB"} \ No newline at end of file diff --git a/packages/system/dist/NostrLink.d.ts b/packages/system/dist/NostrLink.d.ts new file mode 100644 index 00000000..8d22c067 --- /dev/null +++ b/packages/system/dist/NostrLink.d.ts @@ -0,0 +1,13 @@ +import { NostrPrefix } from "."; +export interface NostrLink { + type: NostrPrefix; + id: string; + kind?: number; + author?: string; + relays?: Array; + encode(): string; +} +export declare function validateNostrLink(link: string): boolean; +export declare function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined; +export declare function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink; +//# sourceMappingURL=NostrLink.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NostrLink.d.ts.map b/packages/system/dist/NostrLink.d.ts.map new file mode 100644 index 00000000..ab1d2006 --- /dev/null +++ b/packages/system/dist/NostrLink.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrLink.d.ts","sourceRoot":"","sources":["../src/NostrLink.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA2B,MAAM,GAAG,CAAC;AAEzD,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,IAAI,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAcvD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAM/F;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,CAwEhF"} \ No newline at end of file diff --git a/packages/system/dist/NostrLink.js b/packages/system/dist/NostrLink.js new file mode 100644 index 00000000..18cecd68 --- /dev/null +++ b/packages/system/dist/NostrLink.js @@ -0,0 +1,110 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseNostrLink = exports.tryParseNostrLink = exports.validateNostrLink = void 0; +const Util_1 = require("./Util"); +const _1 = require("."); +function validateNostrLink(link) { + try { + const parsedLink = parseNostrLink(link); + if (!parsedLink) { + return false; + } + if (parsedLink.type === _1.NostrPrefix.PublicKey || parsedLink.type === _1.NostrPrefix.Note) { + return parsedLink.id.length === 64; + } + return true; + } + catch { + return false; + } +} +exports.validateNostrLink = validateNostrLink; +function tryParseNostrLink(link, prefixHint) { + try { + return parseNostrLink(link, prefixHint); + } + catch { + return undefined; + } +} +exports.tryParseNostrLink = tryParseNostrLink; +function parseNostrLink(link, prefixHint) { + const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; + const isPrefix = (prefix) => { + return entity.startsWith(prefix); + }; + if (isPrefix(_1.NostrPrefix.PublicKey)) { + const id = (0, Util_1.bech32ToHex)(entity); + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.PublicKey, + id: id, + encode: () => (0, Util_1.hexToBech32)(_1.NostrPrefix.PublicKey, id), + }; + } + else if (isPrefix(_1.NostrPrefix.Note)) { + const id = (0, Util_1.bech32ToHex)(entity); + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Note, + id: id, + encode: () => (0, Util_1.hexToBech32)(_1.NostrPrefix.Note, id), + }; + } + else if (isPrefix(_1.NostrPrefix.Profile) || isPrefix(_1.NostrPrefix.Event) || isPrefix(_1.NostrPrefix.Address)) { + const decoded = (0, _1.decodeTLV)(entity); + const id = decoded.find(a => a.type === _1.TLVEntryType.Special)?.value; + const relays = decoded.filter(a => a.type === _1.TLVEntryType.Relay).map(a => a.value); + const author = decoded.find(a => a.type === _1.TLVEntryType.Author)?.value; + const kind = decoded.find(a => a.type === _1.TLVEntryType.Kind)?.value; + const encode = () => { + return entity; // return original + }; + if (isPrefix(_1.NostrPrefix.Profile)) { + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Profile, + id, + relays, + kind, + author, + encode, + }; + } + else if (isPrefix(_1.NostrPrefix.Event)) { + if (id.length !== 64) + throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: _1.NostrPrefix.Event, + id, + relays, + kind, + author, + encode, + }; + } + else if (isPrefix(_1.NostrPrefix.Address)) { + return { + type: _1.NostrPrefix.Address, + id, + relays, + kind, + author, + encode, + }; + } + } + else if (prefixHint) { + return { + type: prefixHint, + id: link, + encode: () => (0, Util_1.hexToBech32)(prefixHint, link), + }; + } + throw new Error("Invalid nostr link"); +} +exports.parseNostrLink = parseNostrLink; +//# sourceMappingURL=NostrLink.js.map \ No newline at end of file diff --git a/packages/system/dist/NostrLink.js.map b/packages/system/dist/NostrLink.js.map new file mode 100644 index 00000000..8ad349a3 --- /dev/null +++ b/packages/system/dist/NostrLink.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrLink.js","sourceRoot":"","sources":["../src/NostrLink.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.d.ts b/packages/system/dist/NostrSystem.d.ts new file mode 100644 index 00000000..c684a9be --- /dev/null +++ b/packages/system/dist/NostrSystem.d.ts @@ -0,0 +1,75 @@ +import ExternalStore from "./ExternalStore"; +import { NostrEvent, TaggedRawEvent } from "./Nostr"; +import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { Query } from "./Query"; +import { RelayCache } from "./GossipModel"; +import { NoteStore } from "./NoteCollection"; +import { BuiltRawReqFilter, RequestBuilder } from "./RequestBuilder"; +import { SystemInterface, SystemSnapshot } from "."; +/** + * Manages nostr content retrieval system + */ +export declare class NostrSystem extends ExternalStore implements SystemInterface { + #private; + /** + * All active queries + */ + Queries: Map; + /** + * Handler function for NIP-42 + */ + HandleAuth?: AuthHandler; + constructor(relayCache: RelayCache); + get Sockets(): ConnectionStateSnapshot[]; + /** + * Connect to a NOSTR relay if not already connected + */ + ConnectToRelay(address: string, options: RelaySettings): Promise; + OnRelayDisconnect(id: string): void; + OnEndOfStoredEvents(c: Readonly, sub: string): void; + OnEvent(sub: string, ev: TaggedRawEvent): void; + /** + * + * @param address Relay address URL + */ + ConnectEphemeralRelay(address: string): Promise; + /** + * Disconnect from a relay + */ + DisconnectRelay(address: string): void; + GetQuery(id: string): Query | undefined; + Query(type: { + new (): T; + }, req: RequestBuilder): Query; + SendQuery(q: Query, qSend: BuiltRawReqFilter): Promise<{ + readonly id: string; + readonly start: number; + sent?: number | undefined; + eose?: number | undefined; + close?: number | undefined; + "__#9@#wasForceClosed": boolean; + readonly "__#9@#fnClose": (id: string) => void; + readonly "__#9@#fnProgress": () => void; + readonly relay: string; + readonly filters: import("./Nostr").ReqFilter[]; + readonly connId: string; + sentToRelay(): void; + gotEose(): void; + forceEose(): void; + sendClose(): void; + readonly queued: number; + readonly runtime: number; + readonly responseTime: number; + readonly finished: boolean; + }[]>; + /** + * Send events to writable relays + */ + BroadcastEvent(ev: NostrEvent): void; + /** + * Write an event to a relay then disconnect + */ + WriteOnceToRelay(address: string, ev: NostrEvent): Promise; + takeSnapshot(): SystemSnapshot; +} +//# sourceMappingURL=NostrSystem.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.d.ts.map b/packages/system/dist/NostrSystem.d.ts.map new file mode 100644 index 00000000..6cfd8efc --- /dev/null +++ b/packages/system/dist/NostrSystem.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrSystem.d.ts","sourceRoot":"","sources":["../src/NostrSystem.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC/F,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,GAAG,CAAC;AAEpD;;GAEG;AACH,qBAAa,WAAY,SAAQ,aAAa,CAAC,cAAc,CAAE,YAAW,eAAe;;IAMvF;;OAEG;IACH,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAa;IAExC;;OAEG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC;gBAKb,UAAU,EAAE,UAAU;IAMlC,IAAI,OAAO,IAAI,uBAAuB,EAAE,CAEvC;IAED;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAmB5D,iBAAiB,CAAC,EAAE,EAAE,MAAM;IAM5B,mBAAmB,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,MAAM;IAMxD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc;IAMvC;;;OAGG;IACG,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAiB7E;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM;IAQ/B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIvC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE;QAAE,QAAQ,CAAC,CAAA;KAAE,EAAE,GAAG,EAAE,cAAc,GAAG,KAAK;IAiCrE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;IAmClD;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,UAAU;IAM7B;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU;IAetD,YAAY,IAAI,cAAc;CA2B/B"} \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.js b/packages/system/dist/NostrSystem.js new file mode 100644 index 00000000..305b539d --- /dev/null +++ b/packages/system/dist/NostrSystem.js @@ -0,0 +1,237 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _NostrSystem_instances, _NostrSystem_sockets, _NostrSystem_log, _NostrSystem_relayCache, _NostrSystem_cleanup; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NostrSystem = void 0; +const debug_1 = __importDefault(require("debug")); +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +const Connection_1 = require("./Connection"); +const Query_1 = require("./Query"); +const Util_1 = require("./Util"); +/** + * Manages nostr content retrieval system + */ +class NostrSystem extends ExternalStore_1.default { + constructor(relayCache) { + super(); + _NostrSystem_instances.add(this); + /** + * All currently connected websockets + */ + _NostrSystem_sockets.set(this, new Map()); + /** + * All active queries + */ + this.Queries = new Map(); + _NostrSystem_log.set(this, (0, debug_1.default)("System")); + _NostrSystem_relayCache.set(this, void 0); + __classPrivateFieldSet(this, _NostrSystem_relayCache, relayCache, "f"); + __classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this); + } + get Sockets() { + return [...__classPrivateFieldGet(this, _NostrSystem_sockets, "f").values()].map(a => a.snapshot()); + } + /** + * Connect to a NOSTR relay if not already connected + */ + async ConnectToRelay(address, options) { + try { + const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address)); + if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) { + const c = new Connection_1.Connection(addr, options, this.HandleAuth?.bind(this)); + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c); + c.OnEvent = (s, e) => this.OnEvent(s, e); + c.OnEose = s => this.OnEndOfStoredEvents(c, s); + c.OnDisconnect = id => this.OnRelayDisconnect(id); + await c.Connect(); + } + else { + // update settings if already connected + (0, Util_1.unwrap)(__classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(addr)).Settings = options; + } + } + catch (e) { + console.error(e); + } + } + OnRelayDisconnect(id) { + for (const [, q] of this.Queries) { + q.connectionLost(id); + } + } + OnEndOfStoredEvents(c, sub) { + for (const [, v] of this.Queries) { + v.eose(sub, c); + } + } + OnEvent(sub, ev) { + for (const [, v] of this.Queries) { + v.onEvent(sub, ev); + } + } + /** + * + * @param address Relay address URL + */ + async ConnectEphemeralRelay(address) { + try { + const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address)); + if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) { + const c = new Connection_1.Connection(addr, { read: true, write: false }, this.HandleAuth?.bind(this), true); + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c); + c.OnEvent = (s, e) => this.OnEvent(s, e); + c.OnEose = s => this.OnEndOfStoredEvents(c, s); + c.OnDisconnect = id => this.OnRelayDisconnect(id); + await c.Connect(); + return c; + } + } + catch (e) { + console.error(e); + } + } + /** + * Disconnect from a relay + */ + DisconnectRelay(address) { + const c = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(address); + if (c) { + __classPrivateFieldGet(this, _NostrSystem_sockets, "f").delete(address); + c.Close(); + } + } + GetQuery(id) { + return this.Queries.get(id); + } + Query(type, req) { + const existing = this.Queries.get(req.id); + if (existing) { + const filters = !req.options?.skipDiff + ? req.buildDiff(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f"), existing.filters) + : req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f")); + if (filters.length === 0 && !!req.options?.skipDiff) { + return existing; + } + else { + for (const subQ of filters) { + this.SendQuery(existing, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O from: %O", req.id, v.id, v.filters, existing.filters))); + } + this.notifyChange(); + return existing; + } + } + else { + const store = new type(); + const filters = req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f")); + const q = new Query_1.Query(req.id, store, req.options?.leaveOpen); + this.Queries.set(req.id, q); + for (const subQ of filters) { + this.SendQuery(q, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O", req.id, v.id, v.filters))); + } + this.notifyChange(); + return q; + } + } + async SendQuery(q, qSend) { + if (qSend.relay) { + __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Sending query to %s %O", qSend.relay, qSend); + const s = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(qSend.relay); + if (s) { + const qt = q.sendToRelay(s, qSend); + if (qt) { + return [qt]; + } + } + else { + const nc = await this.ConnectEphemeralRelay(qSend.relay); + if (nc) { + const qt = q.sendToRelay(nc, qSend); + if (qt) { + return [qt]; + } + } + else { + console.warn("Failed to connect to new relay for:", qSend.relay, q); + } + } + } + else { + const ret = []; + for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) { + if (!s.Ephemeral) { + const qt = q.sendToRelay(s, qSend); + if (qt) { + ret.push(qt); + } + } + } + return ret; + } + return []; + } + /** + * Send events to writable relays + */ + BroadcastEvent(ev) { + for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) { + s.SendEvent(ev); + } + } + /** + * Write an event to a relay then disconnect + */ + async WriteOnceToRelay(address, ev) { + return new Promise((resolve, reject) => { + const c = new Connection_1.Connection(address, { write: true, read: false }, this.HandleAuth, true); + const t = setTimeout(reject, 5000); + c.OnConnected = async () => { + clearTimeout(t); + await c.SendAsync(ev); + c.Close(); + resolve(); + }; + c.Connect(); + }); + } + takeSnapshot() { + return { + queries: [...this.Queries.values()].map(a => { + return { + id: a.id, + filters: a.filters, + subFilters: [], + }; + }), + }; + } +} +exports.NostrSystem = NostrSystem; +_NostrSystem_sockets = new WeakMap(), _NostrSystem_log = new WeakMap(), _NostrSystem_relayCache = new WeakMap(), _NostrSystem_instances = new WeakSet(), _NostrSystem_cleanup = function _NostrSystem_cleanup() { + let changed = false; + for (const [k, v] of this.Queries) { + if (v.canRemove()) { + v.sendClose(); + this.Queries.delete(k); + __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Deleted query %s", k); + changed = true; + } + } + if (changed) { + this.notifyChange(); + } + setTimeout(() => __classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this), 1000); +}; +//# sourceMappingURL=NostrSystem.js.map \ No newline at end of file diff --git a/packages/system/dist/NostrSystem.js.map b/packages/system/dist/NostrSystem.js.map new file mode 100644 index 00000000..52f75a20 --- /dev/null +++ b/packages/system/dist/NostrSystem.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NostrSystem.js","sourceRoot":"","sources":["../src/NostrSystem.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.d.ts b/packages/system/dist/NoteCollection.d.ts new file mode 100644 index 00000000..47f8c80c --- /dev/null +++ b/packages/system/dist/NoteCollection.d.ts @@ -0,0 +1,91 @@ +import { TaggedRawEvent } from "."; +export interface StoreSnapshot { + data: TSnapshot | undefined; + clear: () => void; + loading: () => boolean; + add: (ev: Readonly | Readonly>) => void; +} +export declare const EmptySnapshot: StoreSnapshot; +export type NoteStoreSnapshotData = Readonly> | Readonly; +export type NoteStoreHook = () => void; +export type NoteStoreHookRelease = () => void; +export type OnEventCallback = (e: Readonly>) => void; +export type OnEventCallbackRelease = () => void; +export type OnEoseCallback = (c: string) => void; +export type OnEoseCallbackRelease = () => void; +/** + * Generic note store interface + */ +export declare abstract class NoteStore { + abstract add(ev: Readonly | Readonly>): void; + abstract clear(): void; + abstract hook(cb: NoteStoreHook): NoteStoreHookRelease; + abstract getSnapshotData(): NoteStoreSnapshotData | undefined; + abstract onEvent(cb: OnEventCallback): OnEventCallbackRelease; + abstract get snapshot(): StoreSnapshot; + abstract get loading(): boolean; + abstract set loading(v: boolean); +} +export declare abstract class HookedNoteStore implements NoteStore { + #private; + get snapshot(): StoreSnapshot; + get loading(): boolean; + set loading(v: boolean); + abstract add(ev: Readonly | Readonly>): void; + abstract clear(): void; + hook(cb: NoteStoreHook): NoteStoreHookRelease; + getSnapshotData(): TSnapshot | undefined; + onEvent(cb: OnEventCallback): OnEventCallbackRelease; + protected abstract takeSnapshot(): TSnapshot | undefined; + protected onChange(changes: Readonly>): void; +} +/** + * A simple flat container of events with no duplicates + */ +export declare class FlatNoteStore extends HookedNoteStore>> { + #private; + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): TaggedRawEvent[]; +} +/** + * A note store that holds a single replaceable event for a given user defined key generator function + */ +export declare class KeyedReplaceableNoteStore extends HookedNoteStore>> { + #private; + constructor(fn: (ev: TaggedRawEvent) => string); + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): TaggedRawEvent[]; +} +/** + * A note store that holds a single replaceable event + */ +export declare class ReplaceableNoteStore extends HookedNoteStore> { + #private; + add(ev: TaggedRawEvent | Array): void; + clear(): void; + takeSnapshot(): Readonly<{ + relays: string[]; + id: string; + pubkey: string; + created_at: number; + kind: number; + tags: string[][]; + content: string; + sig: string; + }> | undefined; +} +/** + * A note store that holds a single replaceable event per pubkey + */ +export declare class PubkeyReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor(); +} +/** + * A note store that holds a single replaceable event per "pubkey-dtag" + */ +export declare class ParameterizedReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor(); +} +//# sourceMappingURL=NoteCollection.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.d.ts.map b/packages/system/dist/NoteCollection.d.ts.map new file mode 100644 index 00000000..ffe731e5 --- /dev/null +++ b/packages/system/dist/NoteCollection.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NoteCollection.d.ts","sourceRoot":"","sources":["../src/NoteCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAQ,MAAM,GAAG,CAAC;AAGzC,MAAM,WAAW,aAAa,CAAC,SAAS;IACtC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,GAAG,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,KAAK,IAAI,CAAC;CAC/E;AAED,eAAO,MAAM,aAAa,8BASO,CAAC;AAElC,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAC/F,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AACvC,MAAM,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,KAAK,IAAI,CAAC;AAC3E,MAAM,MAAM,sBAAsB,GAAG,MAAM,IAAI,CAAC;AAChD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AACjD,MAAM,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC;AAE/C;;GAEG;AACH,8BAAsB,SAAS;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI;IAClF,QAAQ,CAAC,KAAK,IAAI,IAAI;IAGtB,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,GAAG,oBAAoB;IACtD,QAAQ,CAAC,eAAe,IAAI,qBAAqB,GAAG,SAAS;IAG7D,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,eAAe,GAAG,sBAAsB;IAE7D,QAAQ,KAAK,QAAQ,IAAI,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC9D,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC;IAChC,QAAQ,KAAK,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE;CAClC;AAED,8BAAsB,eAAe,CAAC,SAAS,SAAS,qBAAqB,CAAE,YAAW,SAAS;;IAajG,IAAI,QAAQ,6BAGX;IAED,IAAI,OAAO,IAII,OAAO,CAFrB;IAED,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAGrB;IAED,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI;IAClF,QAAQ,CAAC,KAAK,IAAI,IAAI;IAEtB,IAAI,CAAC,EAAE,EAAE,aAAa,GAAG,oBAAoB;IAQ7C,eAAe;IAKf,OAAO,CAAC,EAAE,EAAE,eAAe,GAAG,sBAAsB;IAcpD,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,SAAS,GAAG,SAAS;IAExD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI;CA0BnE;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;;IAIjF,GAAG,CAAC,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAqB9C,KAAK;IAML,YAAY;CAGb;AAED;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;;gBAIjF,EAAE,EAAE,CAAC,EAAE,EAAE,cAAc,KAAK,MAAM;IAK9C,GAAG,CAAC,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAgB9C,KAAK;IAKL,YAAY;CAGb;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,eAAe,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;;IAGjF,GAAG,CAAC,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAe9C,KAAK;IAKL,YAAY;;;;;;;;;;CAKb;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,yBAAyB;;CAIxE;AAED;;GAEG;AACH,qBAAa,iCAAkC,SAAQ,yBAAyB;;CAO/E"} \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.js b/packages/system/dist/NoteCollection.js new file mode 100644 index 00000000..70e7376c --- /dev/null +++ b/packages/system/dist/NoteCollection.js @@ -0,0 +1,240 @@ +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var _HookedNoteStore_instances, _HookedNoteStore_hooks, _HookedNoteStore_eventHooks, _HookedNoteStore_loading, _HookedNoteStore_storeSnapshot, _HookedNoteStore_needsSnapshot, _HookedNoteStore_nextNotifyTimer, _HookedNoteStore_updateSnapshot, _FlatNoteStore_events, _FlatNoteStore_ids, _KeyedReplaceableNoteStore_keyFn, _KeyedReplaceableNoteStore_events, _ReplaceableNoteStore_event; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ParameterizedReplaceableNoteStore = exports.PubkeyReplaceableNoteStore = exports.ReplaceableNoteStore = exports.KeyedReplaceableNoteStore = exports.FlatNoteStore = exports.HookedNoteStore = exports.NoteStore = exports.EmptySnapshot = void 0; +const Util_1 = require("./Util"); +exports.EmptySnapshot = { + data: undefined, + clear: () => { + // empty + }, + loading: () => true, + add: () => { + // empty + }, +}; +/** + * Generic note store interface + */ +class NoteStore { +} +exports.NoteStore = NoteStore; +class HookedNoteStore { + constructor() { + _HookedNoteStore_instances.add(this); + _HookedNoteStore_hooks.set(this, []); + _HookedNoteStore_eventHooks.set(this, []); + _HookedNoteStore_loading.set(this, true); + _HookedNoteStore_storeSnapshot.set(this, { + clear: () => this.clear(), + loading: () => this.loading, + add: ev => this.add(ev), + data: undefined, + }); + _HookedNoteStore_needsSnapshot.set(this, true); + _HookedNoteStore_nextNotifyTimer.set(this, void 0); + } + get snapshot() { + __classPrivateFieldGet(this, _HookedNoteStore_instances, "m", _HookedNoteStore_updateSnapshot).call(this); + return __classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f"); + } + get loading() { + return __classPrivateFieldGet(this, _HookedNoteStore_loading, "f"); + } + set loading(v) { + __classPrivateFieldSet(this, _HookedNoteStore_loading, v, "f"); + this.onChange([]); + } + hook(cb) { + __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").push(cb); + return () => { + const idx = __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").findIndex(a => a === cb); + __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f").splice(idx, 1); + }; + } + getSnapshotData() { + __classPrivateFieldGet(this, _HookedNoteStore_instances, "m", _HookedNoteStore_updateSnapshot).call(this); + return __classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f").data; + } + onEvent(cb) { + const existing = __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").find(a => a === cb); + if (!existing) { + __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").push(cb); + return () => { + const idx = __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").findIndex(a => a === cb); + __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f").splice(idx, 1); + }; + } + return () => { + //noop + }; + } + onChange(changes) { + __classPrivateFieldSet(this, _HookedNoteStore_needsSnapshot, true, "f"); + if (!__classPrivateFieldGet(this, _HookedNoteStore_nextNotifyTimer, "f")) { + __classPrivateFieldSet(this, _HookedNoteStore_nextNotifyTimer, setTimeout(() => { + __classPrivateFieldSet(this, _HookedNoteStore_nextNotifyTimer, undefined, "f"); + for (const hk of __classPrivateFieldGet(this, _HookedNoteStore_hooks, "f")) { + hk(); + } + }, 500), "f"); + } + if (changes.length > 0) { + for (const hkE of __classPrivateFieldGet(this, _HookedNoteStore_eventHooks, "f")) { + hkE(changes); + } + } + } +} +exports.HookedNoteStore = HookedNoteStore; +_HookedNoteStore_hooks = new WeakMap(), _HookedNoteStore_eventHooks = new WeakMap(), _HookedNoteStore_loading = new WeakMap(), _HookedNoteStore_storeSnapshot = new WeakMap(), _HookedNoteStore_needsSnapshot = new WeakMap(), _HookedNoteStore_nextNotifyTimer = new WeakMap(), _HookedNoteStore_instances = new WeakSet(), _HookedNoteStore_updateSnapshot = function _HookedNoteStore_updateSnapshot() { + if (__classPrivateFieldGet(this, _HookedNoteStore_needsSnapshot, "f")) { + __classPrivateFieldSet(this, _HookedNoteStore_storeSnapshot, { + ...__classPrivateFieldGet(this, _HookedNoteStore_storeSnapshot, "f"), + data: this.takeSnapshot(), + }, "f"); + __classPrivateFieldSet(this, _HookedNoteStore_needsSnapshot, false, "f"); + } +}; +/** + * A simple flat container of events with no duplicates + */ +class FlatNoteStore extends HookedNoteStore { + constructor() { + super(...arguments); + _FlatNoteStore_events.set(this, []); + _FlatNoteStore_ids.set(this, new Set()); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + if (!__classPrivateFieldGet(this, _FlatNoteStore_ids, "f").has(a.id)) { + __classPrivateFieldGet(this, _FlatNoteStore_events, "f").push(a); + __classPrivateFieldGet(this, _FlatNoteStore_ids, "f").add(a.id); + changes.push(a); + } + else { + const existing = __classPrivateFieldGet(this, _FlatNoteStore_events, "f").find(b => b.id === a.id); + if (existing) { + existing.relays = (0, Util_1.appendDedupe)(existing.relays, a.relays); + } + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldSet(this, _FlatNoteStore_events, [], "f"); + __classPrivateFieldGet(this, _FlatNoteStore_ids, "f").clear(); + this.onChange([]); + } + takeSnapshot() { + return [...__classPrivateFieldGet(this, _FlatNoteStore_events, "f")]; + } +} +exports.FlatNoteStore = FlatNoteStore; +_FlatNoteStore_events = new WeakMap(), _FlatNoteStore_ids = new WeakMap(); +/** + * A note store that holds a single replaceable event for a given user defined key generator function + */ +class KeyedReplaceableNoteStore extends HookedNoteStore { + constructor(fn) { + super(); + _KeyedReplaceableNoteStore_keyFn.set(this, void 0); + _KeyedReplaceableNoteStore_events.set(this, new Map()); + __classPrivateFieldSet(this, _KeyedReplaceableNoteStore_keyFn, fn, "f"); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + const keyOnEvent = __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_keyFn, "f").call(this, a); + const existingCreated = __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").get(keyOnEvent)?.created_at ?? 0; + if (a.created_at > existingCreated) { + __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").set(keyOnEvent, a); + changes.push(a); + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").clear(); + this.onChange([]); + } + takeSnapshot() { + return [...__classPrivateFieldGet(this, _KeyedReplaceableNoteStore_events, "f").values()]; + } +} +exports.KeyedReplaceableNoteStore = KeyedReplaceableNoteStore; +_KeyedReplaceableNoteStore_keyFn = new WeakMap(), _KeyedReplaceableNoteStore_events = new WeakMap(); +/** + * A note store that holds a single replaceable event + */ +class ReplaceableNoteStore extends HookedNoteStore { + constructor() { + super(...arguments); + _ReplaceableNoteStore_event.set(this, void 0); + } + add(ev) { + ev = Array.isArray(ev) ? ev : [ev]; + const changes = []; + ev.forEach(a => { + const existingCreated = __classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f")?.created_at ?? 0; + if (a.created_at > existingCreated) { + __classPrivateFieldSet(this, _ReplaceableNoteStore_event, a, "f"); + changes.push(a); + } + }); + if (changes.length > 0) { + this.onChange(changes); + } + } + clear() { + __classPrivateFieldSet(this, _ReplaceableNoteStore_event, undefined, "f"); + this.onChange([]); + } + takeSnapshot() { + if (__classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f")) { + return Object.freeze({ ...__classPrivateFieldGet(this, _ReplaceableNoteStore_event, "f") }); + } + } +} +exports.ReplaceableNoteStore = ReplaceableNoteStore; +_ReplaceableNoteStore_event = new WeakMap(); +/** + * A note store that holds a single replaceable event per pubkey + */ +class PubkeyReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor() { + super(e => e.pubkey); + } +} +exports.PubkeyReplaceableNoteStore = PubkeyReplaceableNoteStore; +/** + * A note store that holds a single replaceable event per "pubkey-dtag" + */ +class ParameterizedReplaceableNoteStore extends KeyedReplaceableNoteStore { + constructor() { + super(ev => { + const dTag = (0, Util_1.findTag)(ev, "d"); + return `${ev.pubkey}-${dTag}`; + }); + } +} +exports.ParameterizedReplaceableNoteStore = ParameterizedReplaceableNoteStore; +//# sourceMappingURL=NoteCollection.js.map \ No newline at end of file diff --git a/packages/system/dist/NoteCollection.js.map b/packages/system/dist/NoteCollection.js.map new file mode 100644 index 00000000..b9630ff9 --- /dev/null +++ b/packages/system/dist/NoteCollection.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NoteCollection.js","sourceRoot":"","sources":["../src/NoteCollection.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.d.ts b/packages/system/dist/ProfileCache.d.ts new file mode 100644 index 00000000..87f4e53f --- /dev/null +++ b/packages/system/dist/ProfileCache.d.ts @@ -0,0 +1,20 @@ +import { HexKey, SystemInterface, TaggedRawEvent } from "."; +import { CacheStore, MetadataCache } from "./cache"; +export declare class ProfileLoaderService { + #private; + /** + * List of pubkeys to fetch metadata for + */ + WantsMetadata: Set; + constructor(system: SystemInterface, cache: CacheStore); + /** + * Request profile metadata for a set of pubkeys + */ + TrackMetadata(pk: HexKey | Array): void; + /** + * Stop tracking metadata for a set of pubkeys + */ + UntrackMetadata(pk: HexKey | Array): void; + onProfileEvent(e: Readonly): Promise; +} +//# sourceMappingURL=ProfileCache.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.d.ts.map b/packages/system/dist/ProfileCache.d.ts.map new file mode 100644 index 00000000..acbcf017 --- /dev/null +++ b/packages/system/dist/ProfileCache.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ProfileCache.d.ts","sourceRoot":"","sources":["../src/ProfileCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,eAAe,EAAE,cAAc,EAA8C,MAAM,GAAG,CAAC;AAEnH,OAAO,EAAE,UAAU,EAAqB,aAAa,EAAE,MAAM,SAAS,CAAC;AAIvE,qBAAa,oBAAoB;;IAI/B;;OAEG;IACH,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;gBAI3B,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC;IAMrE;;OAEG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAUxC;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAQpC,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC;CA4EjD"} \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.js b/packages/system/dist/ProfileCache.js new file mode 100644 index 00000000..98105241 --- /dev/null +++ b/packages/system/dist/ProfileCache.js @@ -0,0 +1,129 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _ProfileLoaderService_instances, _ProfileLoaderService_system, _ProfileLoaderService_cache, _ProfileLoaderService_log, _ProfileLoaderService_FetchMetadata; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ProfileLoaderService = void 0; +const _1 = require("."); +const Const_1 = require("./Const"); +const cache_1 = require("./cache"); +const Util_1 = require("./Util"); +const debug_1 = __importDefault(require("debug")); +class ProfileLoaderService { + constructor(system, cache) { + _ProfileLoaderService_instances.add(this); + _ProfileLoaderService_system.set(this, void 0); + _ProfileLoaderService_cache.set(this, void 0); + /** + * List of pubkeys to fetch metadata for + */ + this.WantsMetadata = new Set(); + _ProfileLoaderService_log.set(this, (0, debug_1.default)("ProfileCache")); + __classPrivateFieldSet(this, _ProfileLoaderService_system, system, "f"); + __classPrivateFieldSet(this, _ProfileLoaderService_cache, cache, "f"); + __classPrivateFieldGet(this, _ProfileLoaderService_instances, "m", _ProfileLoaderService_FetchMetadata).call(this); + } + /** + * Request profile metadata for a set of pubkeys + */ + TrackMetadata(pk) { + const bufferNow = []; + for (const p of Array.isArray(pk) ? pk : [pk]) { + if (p.length > 0 && this.WantsMetadata.add(p)) { + bufferNow.push(p); + } + } + __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").buffer(bufferNow); + } + /** + * Stop tracking metadata for a set of pubkeys + */ + UntrackMetadata(pk) { + for (const p of Array.isArray(pk) ? pk : [pk]) { + if (p.length > 0) { + this.WantsMetadata.delete(p); + } + } + } + async onProfileEvent(e) { + const profile = (0, cache_1.mapEventToProfile)(e); + if (profile) { + await __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").update(profile); + } + } +} +exports.ProfileLoaderService = ProfileLoaderService; +_ProfileLoaderService_system = new WeakMap(), _ProfileLoaderService_cache = new WeakMap(), _ProfileLoaderService_log = new WeakMap(), _ProfileLoaderService_instances = new WeakSet(), _ProfileLoaderService_FetchMetadata = async function _ProfileLoaderService_FetchMetadata() { + const missingFromCache = await __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").buffer([...this.WantsMetadata]); + const expire = (0, Util_1.unixNowMs)() - Const_1.ProfileCacheExpire; + const expired = [...this.WantsMetadata] + .filter(a => !missingFromCache.includes(a)) + .filter(a => (__classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").getFromCache(a)?.loaded ?? 0) < expire); + const missing = new Set([...missingFromCache, ...expired]); + if (missing.size > 0) { + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Wants profiles: %d missing, %d expired", missingFromCache.length, expired.length); + const sub = new _1.RequestBuilder("profiles"); + sub + .withOptions({ + skipDiff: true, + }) + .withFilter() + .kinds([_1.EventKind.SetMetadata]) + .authors([...missing]); + const newProfiles = new Set(); + const q = __classPrivateFieldGet(this, _ProfileLoaderService_system, "f").Query(_1.PubkeyReplaceableNoteStore, sub); + const feed = q?.feed ?? new _1.PubkeyReplaceableNoteStore(); + // never release this callback, it will stop firing anyway after eose + const releaseOnEvent = feed.onEvent(async (e) => { + for (const pe of e) { + newProfiles.add(pe.id); + await this.onProfileEvent(pe); + } + }); + const results = await new Promise(resolve => { + let timeout = undefined; + const release = feed.hook(() => { + if (!feed.loading) { + clearTimeout(timeout); + resolve(feed.getSnapshotData() ?? []); + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Profiles finished: %s", sub.id); + release(); + } + }); + timeout = setTimeout(() => { + release(); + resolve(feed.getSnapshotData() ?? []); + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "Profiles timeout: %s", sub.id); + }, 5000); + }); + releaseOnEvent(); + const couldNotFetch = [...missing].filter(a => !results.some(b => b.pubkey === a)); + if (couldNotFetch.length > 0) { + __classPrivateFieldGet(this, _ProfileLoaderService_log, "f").call(this, "No profiles: %o", couldNotFetch); + const empty = couldNotFetch.map(a => __classPrivateFieldGet(this, _ProfileLoaderService_cache, "f").update({ + pubkey: a, + loaded: (0, Util_1.unixNowMs)() - Const_1.ProfileCacheExpire + 5000, + created: 69, + })); + await Promise.all(empty); + } + // When we fetch an expired profile and its the same as what we already have + // onEvent is not fired and the loaded timestamp never gets updated + const expiredSame = results.filter(a => !newProfiles.has(a.id) && expired.includes(a.pubkey)); + await Promise.all(expiredSame.map(v => this.onProfileEvent(v))); + } + setTimeout(() => __classPrivateFieldGet(this, _ProfileLoaderService_instances, "m", _ProfileLoaderService_FetchMetadata).call(this), 500); +}; +//# sourceMappingURL=ProfileCache.js.map \ No newline at end of file diff --git a/packages/system/dist/ProfileCache.js.map b/packages/system/dist/ProfileCache.js.map new file mode 100644 index 00000000..2722da34 --- /dev/null +++ b/packages/system/dist/ProfileCache.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ProfileCache.js","sourceRoot":"","sources":["../src/ProfileCache.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Query.d.ts b/packages/system/dist/Query.d.ts new file mode 100644 index 00000000..03469640 --- /dev/null +++ b/packages/system/dist/Query.d.ts @@ -0,0 +1,86 @@ +import { Connection, ReqFilter, TaggedRawEvent } from "."; +import { NoteStore } from "./NoteCollection"; +import { BuiltRawReqFilter } from "./RequestBuilder"; +/** + * Tracing for relay query status + */ +declare class QueryTrace { + #private; + readonly relay: string; + readonly filters: Array; + readonly connId: string; + readonly id: string; + readonly start: number; + sent?: number; + eose?: number; + close?: number; + constructor(relay: string, filters: Array, connId: string, fnClose: (id: string) => void, fnProgress: () => void); + sentToRelay(): void; + gotEose(): void; + forceEose(): void; + sendClose(): void; + /** + * Time spent in queue + */ + get queued(): number; + /** + * Total query runtime + */ + get runtime(): number; + /** + * Total time spent waiting for relay to respond + */ + get responseTime(): number; + /** + * If tracing is finished, we got EOSE or timeout + */ + get finished(): boolean; +} +export interface QueryBase { + /** + * Uniquie ID of this query + */ + id: string; + /** + * The query payload (REQ filters) + */ + filters: Array; + /** + * List of relays to send this query to + */ + relays?: Array; +} +/** + * Active or queued query on the system + */ +export declare class Query implements QueryBase { + #private; + /** + * Uniquie ID of this query + */ + id: string; + constructor(id: string, feed: NoteStore, leaveOpen?: boolean); + canRemove(): boolean; + /** + * Recompute the complete set of compressed filters from all query traces + */ + get filters(): ReqFilter[]; + get feed(): NoteStore; + onEvent(sub: string, e: TaggedRawEvent): void; + /** + * This function should be called when this Query object and FeedStore is no longer needed + */ + cancel(): void; + uncancel(): void; + cleanup(): void; + sendToRelay(c: Connection, subq: BuiltRawReqFilter): QueryTrace | undefined; + connectionLost(id: string): void; + sendClose(): void; + eose(sub: string, conn: Readonly): void; + /** + * Get the progress to EOSE, can be used to determine when we should load more content + */ + get progress(): number; +} +export {}; +//# sourceMappingURL=Query.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Query.d.ts.map b/packages/system/dist/Query.d.ts.map new file mode 100644 index 00000000..e3da2f8c --- /dev/null +++ b/packages/system/dist/Query.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../src/Query.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAQ,cAAc,EAAE,MAAM,GAAG,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;GAEG;AACH,cAAM,UAAU;;IAWZ,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAZzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;gBAMJ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,EACzB,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,EAC7B,UAAU,EAAE,MAAM,IAAI;IAQxB,WAAW;IAKX,OAAO;IAKP,SAAS;IAOT,SAAS;IAMT;;OAEG;IACH,IAAI,MAAM,WAET;IAED;;OAEG;IACH,IAAI,OAAO,WAEV;IAED;;OAEG;IACH,IAAI,YAAY,WAEf;IAED;;OAEG;IACH,IAAI,QAAQ,YAEX;CACF;AAED,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAE1B;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS;;IACrC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;gBA8BC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO;IAO5D,SAAS;IAIT;;OAEG;IACH,IAAI,OAAO,gBAEV;IAED,IAAI,IAAI,cAEP;IAED,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc;IAStC;;OAEG;IACH,MAAM;IAIN,QAAQ;IAIR,OAAO;IAIP,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,iBAAiB;IAOlD,cAAc,CAAC,EAAE,EAAE,MAAM;IAIzB,SAAS;IAOT,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC;IAQ5C;;OAEG;IACH,IAAI,QAAQ,WAMX;CA6DF"} \ No newline at end of file diff --git a/packages/system/dist/Query.js b/packages/system/dist/Query.js new file mode 100644 index 00000000..78b291fa --- /dev/null +++ b/packages/system/dist/Query.js @@ -0,0 +1,228 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _QueryTrace_wasForceClosed, _QueryTrace_fnClose, _QueryTrace_fnProgress, _Query_instances, _Query_tracing, _Query_leaveOpen, _Query_cancelAt, _Query_checkTrace, _Query_feed, _Query_log, _Query_allFilters, _Query_onProgress, _Query_stopCheckTraces, _Query_checkTraces, _Query_canSendQuery, _Query_sendQueryInternal, _Query_reComputeFilters; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Query = void 0; +const uuid_1 = require("uuid"); +const debug_1 = __importDefault(require("debug")); +const _1 = require("."); +const Util_1 = require("./Util"); +const RequestMerger_1 = require("./RequestMerger"); +const RequestExpander_1 = require("./RequestExpander"); +/** + * Tracing for relay query status + */ +class QueryTrace { + constructor(relay, filters, connId, fnClose, fnProgress) { + this.relay = relay; + this.filters = filters; + this.connId = connId; + _QueryTrace_wasForceClosed.set(this, false); + _QueryTrace_fnClose.set(this, void 0); + _QueryTrace_fnProgress.set(this, void 0); + this.id = (0, uuid_1.v4)(); + this.start = (0, Util_1.unixNowMs)(); + __classPrivateFieldSet(this, _QueryTrace_fnClose, fnClose, "f"); + __classPrivateFieldSet(this, _QueryTrace_fnProgress, fnProgress, "f"); + } + sentToRelay() { + this.sent = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + gotEose() { + this.eose = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + forceEose() { + this.eose = (0, Util_1.unixNowMs)(); + __classPrivateFieldSet(this, _QueryTrace_wasForceClosed, true, "f"); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + this.sendClose(); + } + sendClose() { + this.close = (0, Util_1.unixNowMs)(); + __classPrivateFieldGet(this, _QueryTrace_fnClose, "f").call(this, this.id); + __classPrivateFieldGet(this, _QueryTrace_fnProgress, "f").call(this); + } + /** + * Time spent in queue + */ + get queued() { + return (this.sent === undefined ? (0, Util_1.unixNowMs)() : __classPrivateFieldGet(this, _QueryTrace_wasForceClosed, "f") ? (0, Util_1.unwrap)(this.eose) : this.sent) - this.start; + } + /** + * Total query runtime + */ + get runtime() { + return (this.eose === undefined ? (0, Util_1.unixNowMs)() : this.eose) - this.start; + } + /** + * Total time spent waiting for relay to respond + */ + get responseTime() { + return this.finished ? (0, Util_1.unwrap)(this.eose) - (0, Util_1.unwrap)(this.sent) : 0; + } + /** + * If tracing is finished, we got EOSE or timeout + */ + get finished() { + return this.eose !== undefined; + } +} +_QueryTrace_wasForceClosed = new WeakMap(), _QueryTrace_fnClose = new WeakMap(), _QueryTrace_fnProgress = new WeakMap(); +/** + * Active or queued query on the system + */ +class Query { + constructor(id, feed, leaveOpen) { + _Query_instances.add(this); + /** + * Which relays this query has already been executed on + */ + _Query_tracing.set(this, []); + /** + * Leave the query open until its removed + */ + _Query_leaveOpen.set(this, false); + /** + * Time when this query can be removed + */ + _Query_cancelAt.set(this, void 0); + /** + * Timer used to track tracing status + */ + _Query_checkTrace.set(this, void 0); + /** + * Feed object which collects events + */ + _Query_feed.set(this, void 0); + _Query_log.set(this, (0, debug_1.default)("Query")); + _Query_allFilters.set(this, []); + this.id = id; + __classPrivateFieldSet(this, _Query_feed, feed, "f"); + __classPrivateFieldSet(this, _Query_leaveOpen, leaveOpen ?? false, "f"); + __classPrivateFieldGet(this, _Query_instances, "m", _Query_checkTraces).call(this); + } + canRemove() { + return __classPrivateFieldGet(this, _Query_cancelAt, "f") !== undefined && __classPrivateFieldGet(this, _Query_cancelAt, "f") < (0, Util_1.unixNowMs)(); + } + /** + * Recompute the complete set of compressed filters from all query traces + */ + get filters() { + return __classPrivateFieldGet(this, _Query_allFilters, "f"); + } + get feed() { + return __classPrivateFieldGet(this, _Query_feed, "f"); + } + onEvent(sub, e) { + for (const t of __classPrivateFieldGet(this, _Query_tracing, "f")) { + if (t.id === sub) { + this.feed.add(e); + break; + } + } + } + /** + * This function should be called when this Query object and FeedStore is no longer needed + */ + cancel() { + __classPrivateFieldSet(this, _Query_cancelAt, (0, Util_1.unixNowMs)() + 5000, "f"); + } + uncancel() { + __classPrivateFieldSet(this, _Query_cancelAt, undefined, "f"); + } + cleanup() { + __classPrivateFieldGet(this, _Query_instances, "m", _Query_stopCheckTraces).call(this); + } + sendToRelay(c, subq) { + if (!__classPrivateFieldGet(this, _Query_instances, "m", _Query_canSendQuery).call(this, c, subq)) { + return; + } + return __classPrivateFieldGet(this, _Query_instances, "m", _Query_sendQueryInternal).call(this, c, subq); + } + connectionLost(id) { + __classPrivateFieldGet(this, _Query_tracing, "f").filter(a => a.connId == id).forEach(a => a.forceEose()); + } + sendClose() { + for (const qt of __classPrivateFieldGet(this, _Query_tracing, "f")) { + qt.sendClose(); + } + this.cleanup(); + } + eose(sub, conn) { + const qt = __classPrivateFieldGet(this, _Query_tracing, "f").find(a => a.id === sub && a.connId === conn.Id); + qt?.gotEose(); + if (!__classPrivateFieldGet(this, _Query_leaveOpen, "f")) { + qt?.sendClose(); + } + } + /** + * Get the progress to EOSE, can be used to determine when we should load more content + */ + get progress() { + const thisProgress = __classPrivateFieldGet(this, _Query_tracing, "f").reduce((acc, v) => (acc += v.finished ? 1 : 0), 0) / __classPrivateFieldGet(this, _Query_tracing, "f").length; + if (isNaN(thisProgress)) { + return 0; + } + return thisProgress; + } +} +exports.Query = Query; +_Query_tracing = new WeakMap(), _Query_leaveOpen = new WeakMap(), _Query_cancelAt = new WeakMap(), _Query_checkTrace = new WeakMap(), _Query_feed = new WeakMap(), _Query_log = new WeakMap(), _Query_allFilters = new WeakMap(), _Query_instances = new WeakSet(), _Query_onProgress = function _Query_onProgress() { + const isFinished = this.progress === 1; + if (this.feed.loading !== isFinished) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "%s loading=%s, progress=%d", this.id, this.feed.loading, this.progress); + this.feed.loading = isFinished; + } +}, _Query_stopCheckTraces = function _Query_stopCheckTraces() { + if (__classPrivateFieldGet(this, _Query_checkTrace, "f")) { + clearInterval(__classPrivateFieldGet(this, _Query_checkTrace, "f")); + } +}, _Query_checkTraces = function _Query_checkTraces() { + __classPrivateFieldGet(this, _Query_instances, "m", _Query_stopCheckTraces).call(this); + __classPrivateFieldSet(this, _Query_checkTrace, setInterval(() => { + for (const v of __classPrivateFieldGet(this, _Query_tracing, "f")) { + if (v.runtime > 5000 && !v.finished) { + v.forceEose(); + } + } + }, 500), "f"); +}, _Query_canSendQuery = function _Query_canSendQuery(c, q) { + if (q.relay && q.relay !== c.Address) { + return false; + } + if (!q.relay && c.Ephemeral) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "Cant send non-specific REQ to ephemeral connection %O %O %O", q, q.relay, c); + return false; + } + if (q.filters.some(a => a.search) && !c.SupportsNip(_1.Nips.Search)) { + __classPrivateFieldGet(this, _Query_log, "f").call(this, "Cant send REQ to non-search relay", c.Address); + return false; + } + return true; +}, _Query_sendQueryInternal = function _Query_sendQueryInternal(c, q) { + const qt = new QueryTrace(c.Address, q.filters, c.Id, x => c.CloseReq(x), () => __classPrivateFieldGet(this, _Query_instances, "m", _Query_onProgress).call(this)); + __classPrivateFieldGet(this, _Query_tracing, "f").push(qt); + __classPrivateFieldGet(this, _Query_instances, "m", _Query_reComputeFilters).call(this); + c.QueueReq(["REQ", qt.id, ...q.filters], () => qt.sentToRelay()); + return qt; +}, _Query_reComputeFilters = function _Query_reComputeFilters() { + console.time("reComputeFilters"); + __classPrivateFieldSet(this, _Query_allFilters, (0, RequestMerger_1.flatMerge)(__classPrivateFieldGet(this, _Query_tracing, "f").flatMap(a => a.filters).flatMap(RequestExpander_1.expandFilter)), "f"); + console.timeEnd("reComputeFilters"); +}; +//# sourceMappingURL=Query.js.map \ No newline at end of file diff --git a/packages/system/dist/Query.js.map b/packages/system/dist/Query.js.map new file mode 100644 index 00000000..56d1e707 --- /dev/null +++ b/packages/system/dist/Query.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.js","sourceRoot":"","sources":["../src/Query.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.d.ts b/packages/system/dist/RelayInfo.d.ts new file mode 100644 index 00000000..0ffe9742 --- /dev/null +++ b/packages/system/dist/RelayInfo.d.ts @@ -0,0 +1,17 @@ +export interface RelayInfo { + name?: string; + description?: string; + pubkey?: string; + contact?: string; + supported_nips?: number[]; + software?: string; + version?: string; + limitation?: { + payment_required: boolean; + max_subscriptions: number; + max_filters: number; + max_event_tags: number; + auth_required: boolean; + }; +} +//# sourceMappingURL=RelayInfo.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.d.ts.map b/packages/system/dist/RelayInfo.d.ts.map new file mode 100644 index 00000000..c52f7495 --- /dev/null +++ b/packages/system/dist/RelayInfo.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RelayInfo.d.ts","sourceRoot":"","sources":["../src/RelayInfo.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QACX,gBAAgB,EAAE,OAAO,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;CACH"} \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.js b/packages/system/dist/RelayInfo.js new file mode 100644 index 00000000..0591ac98 --- /dev/null +++ b/packages/system/dist/RelayInfo.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=RelayInfo.js.map \ No newline at end of file diff --git a/packages/system/dist/RelayInfo.js.map b/packages/system/dist/RelayInfo.js.map new file mode 100644 index 00000000..4fff9c16 --- /dev/null +++ b/packages/system/dist/RelayInfo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RelayInfo.js","sourceRoot":"","sources":["../src/RelayInfo.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.d.ts b/packages/system/dist/RequestBuilder.d.ts new file mode 100644 index 00000000..94ef5649 --- /dev/null +++ b/packages/system/dist/RequestBuilder.d.ts @@ -0,0 +1,93 @@ +import { ReqFilter, u256, HexKey, EventKind } from "."; +import { RelayCache } from "./GossipModel"; +/** + * Which strategy is used when building REQ filters + */ +export declare enum RequestStrategy { + /** + * Use the users default relays to fetch events, + * this is the fallback option when there is no better way to query a given filter set + */ + DefaultRelays = 1, + /** + * Using a cached copy of the authors relay lists NIP-65, split a given set of request filters by pubkey + */ + AuthorsRelays = 2, + /** + * Relay hints are usually provided when using replies + */ + RelayHintedEventIds = 3 +} +/** + * A built REQ filter ready for sending to System + */ +export interface BuiltRawReqFilter { + filters: Array; + relay: string; + strategy: RequestStrategy; +} +export interface RequestBuilderOptions { + leaveOpen?: boolean; + relays?: Array; + /** + * Do not apply diff logic and always use full filters for query + */ + skipDiff?: boolean; +} +/** + * Nostr REQ builder + */ +export declare class RequestBuilder { + #private; + id: string; + constructor(id: string); + get numFilters(): number; + get options(): RequestBuilderOptions | undefined; + withFilter(): RequestFilterBuilder; + withOptions(opt: RequestBuilderOptions): this; + buildRaw(): Array; + build(relays: RelayCache): Array; + /** + * Detects a change in request from a previous set of filters + * @param q All previous filters merged + * @returns + */ + buildDiff(relays: RelayCache, filters: Array): Array; +} +/** + * Builder class for a single request filter + */ +export declare class RequestFilterBuilder { + #private; + get filter(): { + ids?: string[] | undefined; /** + * Relay hints are usually provided when using replies + */ + authors?: string[] | undefined; + kinds?: number[] | undefined; + "#e"?: string[] | undefined; + "#p"?: string[] | undefined; + "#t"?: string[] | undefined; + "#d"?: string[] | undefined; + "#r"?: string[] | undefined; + search?: string | undefined; + since?: number | undefined; + until?: number | undefined; + limit?: number | undefined; + }; + get relayHints(): Map; + ids(ids: Array): this; + id(id: u256, relay?: string): this; + authors(authors?: Array): this; + kinds(kinds?: Array): this; + since(since?: number): this; + until(until?: number): this; + limit(limit?: number): this; + tag(key: "e" | "p" | "d" | "t" | "r", value?: Array): this; + search(keyword?: string): this; + /** + * Build/expand this filter into a set of relay specific queries + */ + build(relays: RelayCache, id: string): Array; +} +//# sourceMappingURL=RequestBuilder.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.d.ts.map b/packages/system/dist/RequestBuilder.d.ts.map new file mode 100644 index 00000000..5b037973 --- /dev/null +++ b/packages/system/dist/RequestBuilder.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestBuilder.d.ts","sourceRoot":"","sources":["../src/RequestBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAGvD,OAAO,EAAE,UAAU,EAA6C,MAAM,eAAe,CAAC;AAGtF;;GAEG;AACH,oBAAY,eAAe;IACzB;;;OAGG;IACH,aAAa,IAAI;IAEjB;;OAEG;IACH,aAAa,IAAI;IAEjB;;OAEG;IACH,mBAAmB,IAAI;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,cAAc;;IACzB,EAAE,EAAE,MAAM,CAAC;gBAIC,EAAE,EAAE,MAAM;IAKtB,IAAI,UAAU,WAEb;IAED,IAAI,OAAO,sCAEV;IAED,UAAU;IAMV,WAAW,CAAC,GAAG,EAAE,qBAAqB;IAQtC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC;IAI5B,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAKnD;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC;CAyCnF;AAED;;GAEG;AACH,qBAAa,oBAAoB;;IAI/B,IAAI,MAAM;oCA3HV;;WAEG;;;;;;;;;;;;MA2HF;IAED,IAAI,UAAU,0BAEb;IAED,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC;IAKpB,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM;IAO3B,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;IAM/B,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAM9B,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM;IAMpB,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;IAM3D,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM;IAMvB;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC;CAuChE"} \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.js b/packages/system/dist/RequestBuilder.js new file mode 100644 index 00000000..b6cdc0b7 --- /dev/null +++ b/packages/system/dist/RequestBuilder.js @@ -0,0 +1,225 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _RequestBuilder_instances, _RequestBuilder_builders, _RequestBuilder_options, _RequestBuilder_groupByRelay, _RequestFilterBuilder_filter, _RequestFilterBuilder_relayHints; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RequestFilterBuilder = exports.RequestBuilder = exports.RequestStrategy = void 0; +const Util_1 = require("./Util"); +const RequestSplitter_1 = require("./RequestSplitter"); +const GossipModel_1 = require("./GossipModel"); +const RequestMerger_1 = require("./RequestMerger"); +/** + * Which strategy is used when building REQ filters + */ +var RequestStrategy; +(function (RequestStrategy) { + /** + * Use the users default relays to fetch events, + * this is the fallback option when there is no better way to query a given filter set + */ + RequestStrategy[RequestStrategy["DefaultRelays"] = 1] = "DefaultRelays"; + /** + * Using a cached copy of the authors relay lists NIP-65, split a given set of request filters by pubkey + */ + RequestStrategy[RequestStrategy["AuthorsRelays"] = 2] = "AuthorsRelays"; + /** + * Relay hints are usually provided when using replies + */ + RequestStrategy[RequestStrategy["RelayHintedEventIds"] = 3] = "RelayHintedEventIds"; +})(RequestStrategy = exports.RequestStrategy || (exports.RequestStrategy = {})); +/** + * Nostr REQ builder + */ +class RequestBuilder { + constructor(id) { + _RequestBuilder_instances.add(this); + _RequestBuilder_builders.set(this, void 0); + _RequestBuilder_options.set(this, void 0); + this.id = id; + __classPrivateFieldSet(this, _RequestBuilder_builders, [], "f"); + } + get numFilters() { + return __classPrivateFieldGet(this, _RequestBuilder_builders, "f").length; + } + get options() { + return __classPrivateFieldGet(this, _RequestBuilder_options, "f"); + } + withFilter() { + const ret = new RequestFilterBuilder(); + __classPrivateFieldGet(this, _RequestBuilder_builders, "f").push(ret); + return ret; + } + withOptions(opt) { + __classPrivateFieldSet(this, _RequestBuilder_options, { + ...__classPrivateFieldGet(this, _RequestBuilder_options, "f"), + ...opt, + }, "f"); + return this; + } + buildRaw() { + return __classPrivateFieldGet(this, _RequestBuilder_builders, "f").map(f => f.filter); + } + build(relays) { + const expanded = __classPrivateFieldGet(this, _RequestBuilder_builders, "f").flatMap(a => a.build(relays, this.id)); + return __classPrivateFieldGet(this, _RequestBuilder_instances, "m", _RequestBuilder_groupByRelay).call(this, expanded); + } + /** + * Detects a change in request from a previous set of filters + * @param q All previous filters merged + * @returns + */ + buildDiff(relays, filters) { + const next = this.buildRaw(); + const diff = (0, RequestSplitter_1.diffFilters)(filters, next); + if (diff.changed) { + return (0, GossipModel_1.splitAllByWriteRelays)(relays, diff.added).map(a => { + return { + strategy: RequestStrategy.AuthorsRelays, + filters: a.filters, + relay: a.relay, + }; + }); + } + return []; + } +} +exports.RequestBuilder = RequestBuilder; +_RequestBuilder_builders = new WeakMap(), _RequestBuilder_options = new WeakMap(), _RequestBuilder_instances = new WeakSet(), _RequestBuilder_groupByRelay = function _RequestBuilder_groupByRelay(expanded) { + const relayMerged = expanded.reduce((acc, v) => { + const existing = acc.get(v.relay); + if (existing) { + existing.push(v); + } + else { + acc.set(v.relay, [v]); + } + return acc; + }, new Map()); + const filtersSquashed = [...relayMerged.values()].map(a => { + return { + filters: (0, RequestMerger_1.mergeSimilar)(a.flatMap(b => b.filters)), + relay: a[0].relay, + strategy: a[0].strategy, + }; + }); + return filtersSquashed; +}; +/** + * Builder class for a single request filter + */ +class RequestFilterBuilder { + constructor() { + _RequestFilterBuilder_filter.set(this, {}); + _RequestFilterBuilder_relayHints.set(this, new Map()); + } + get filter() { + return { ...__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f") }; + } + get relayHints() { + return new Map(__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f")); + } + ids(ids) { + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids, ids); + return this; + } + id(id, relay) { + if (relay) { + __classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").set(id, (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").get(id), [relay])); + } + return this.ids([id]); + } + authors(authors) { + if (!authors) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors, authors); + return this; + } + kinds(kinds) { + if (!kinds) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").kinds = (0, Util_1.appendDedupe)(__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").kinds, kinds); + return this; + } + since(since) { + if (!since) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").since = since; + return this; + } + until(until) { + if (!until) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").until = until; + return this; + } + limit(limit) { + if (!limit) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").limit = limit; + return this; + } + tag(key, value) { + if (!value) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f")[`#${key}`] = value; + return this; + } + search(keyword) { + if (!keyword) + return this; + __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").search = keyword; + return this; + } + /** + * Build/expand this filter into a set of relay specific queries + */ + build(relays, id) { + // when querying for specific event ids with relay hints + // take the first approach which is to split the filter by relay + if (__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").ids && __classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").size > 0) { + const relays = (0, Util_1.dedupe)([...__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").values()].flat()); + return relays.map(r => { + return { + filters: [ + { + ...__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f"), + ids: [...__classPrivateFieldGet(this, _RequestFilterBuilder_relayHints, "f").entries()].filter(([, v]) => v.includes(r)).map(([k]) => k), + }, + ], + relay: r, + strategy: RequestStrategy.RelayHintedEventIds, + }; + }); + } + // If any authors are set use the gossip model to fetch data for each author + if (__classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f").authors) { + const split = (0, GossipModel_1.splitByWriteRelays)(relays, __classPrivateFieldGet(this, _RequestFilterBuilder_filter, "f")); + return split.map(a => { + return { + filters: [a.filter], + relay: a.relay, + strategy: RequestStrategy.AuthorsRelays, + }; + }); + } + return [ + { + filters: [this.filter], + relay: "", + strategy: RequestStrategy.DefaultRelays, + }, + ]; + } +} +exports.RequestFilterBuilder = RequestFilterBuilder; +_RequestFilterBuilder_filter = new WeakMap(), _RequestFilterBuilder_relayHints = new WeakMap(); +//# sourceMappingURL=RequestBuilder.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestBuilder.js.map b/packages/system/dist/RequestBuilder.js.map new file mode 100644 index 00000000..74865223 --- /dev/null +++ b/packages/system/dist/RequestBuilder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestBuilder.js","sourceRoot":"","sources":["../src/RequestBuilder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.d.ts b/packages/system/dist/RequestExpander.d.ts new file mode 100644 index 00000000..83b92600 --- /dev/null +++ b/packages/system/dist/RequestExpander.d.ts @@ -0,0 +1,20 @@ +import { u256, ReqFilter } from "./Nostr"; +export interface FlatReqFilter { + ids?: u256; + authors?: u256; + kinds?: number; + "#e"?: u256; + "#p"?: u256; + "#t"?: string; + "#d"?: string; + "#r"?: string; + search?: string; + since?: number; + until?: number; + limit?: number; +} +/** + * Expand a filter into its most fine grained form + */ +export declare function expandFilter(f: ReqFilter): Array; +//# sourceMappingURL=RequestExpander.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.d.ts.map b/packages/system/dist/RequestExpander.d.ts.map new file mode 100644 index 00000000..2f0419f8 --- /dev/null +++ b/packages/system/dist/RequestExpander.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestExpander.d.ts","sourceRoot":"","sources":["../src/RequestExpander.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,CA2B/D"} \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.js b/packages/system/dist/RequestExpander.js new file mode 100644 index 00000000..5cab53de --- /dev/null +++ b/packages/system/dist/RequestExpander.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.expandFilter = void 0; +/** + * Expand a filter into its most fine grained form + */ +function expandFilter(f) { + const ret = []; + const src = Object.entries(f); + const keys = src.filter(([, v]) => Array.isArray(v)).map(a => a[0]); + const props = src.filter(([, v]) => !Array.isArray(v)); + function generateCombinations(index, currentCombination) { + if (index === keys.length) { + ret.push(currentCombination); + return; + } + const key = keys[index]; + const values = f[key]; + for (let i = 0; i < values.length; i++) { + const value = values[i]; + const updatedCombination = { ...currentCombination, [key]: value }; + generateCombinations(index + 1, updatedCombination); + } + } + generateCombinations(0, { + ...Object.fromEntries(props), + }); + return ret; +} +exports.expandFilter = expandFilter; +//# sourceMappingURL=RequestExpander.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestExpander.js.map b/packages/system/dist/RequestExpander.js.map new file mode 100644 index 00000000..a347f38d --- /dev/null +++ b/packages/system/dist/RequestExpander.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestExpander.js","sourceRoot":"","sources":["../src/RequestExpander.ts"],"names":[],"mappings":";;;AAiBA;;GAEG;AACH,SAAgB,YAAY,CAAC,CAAY;IACvC,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,SAAS,oBAAoB,CAAC,KAAa,EAAE,kBAAiC;QAC5E,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE;YACzB,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC7B,OAAO;SACR;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,MAAM,GAAI,CAA4C,CAAC,GAAG,CAAC,CAAC;QAElE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,kBAAkB,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;YACnE,oBAAoB,CAAC,KAAK,GAAG,CAAC,EAAE,kBAAkB,CAAC,CAAC;SACrD;IACH,CAAC;IAED,oBAAoB,CAAC,CAAC,EAAE;QACtB,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;KAC7B,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC;AA3BD,oCA2BC"} \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.d.ts b/packages/system/dist/RequestMatcher.d.ts new file mode 100644 index 00000000..82948dca --- /dev/null +++ b/packages/system/dist/RequestMatcher.d.ts @@ -0,0 +1,3 @@ +import { NostrEvent, ReqFilter } from "./Nostr"; +export declare function eventMatchesFilter(ev: NostrEvent, filter: ReqFilter): boolean; +//# sourceMappingURL=RequestMatcher.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.d.ts.map b/packages/system/dist/RequestMatcher.d.ts.map new file mode 100644 index 00000000..e0dd95f6 --- /dev/null +++ b/packages/system/dist/RequestMatcher.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMatcher.d.ts","sourceRoot":"","sources":["../src/RequestMatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,WAiBnE"} \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.js b/packages/system/dist/RequestMatcher.js new file mode 100644 index 00000000..81583f43 --- /dev/null +++ b/packages/system/dist/RequestMatcher.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.eventMatchesFilter = void 0; +function eventMatchesFilter(ev, filter) { + if (!(filter.ids?.includes(ev.id) ?? false)) { + return false; + } + if (!(filter.authors?.includes(ev.pubkey) ?? false)) { + return false; + } + if (!(filter.kinds?.includes(ev.kind) ?? false)) { + return false; + } + if (filter.since && ev.created_at < filter.since) { + return false; + } + if (filter.until && ev.created_at > filter.until) { + return false; + } + return true; +} +exports.eventMatchesFilter = eventMatchesFilter; +//# sourceMappingURL=RequestMatcher.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestMatcher.js.map b/packages/system/dist/RequestMatcher.js.map new file mode 100644 index 00000000..dcb35ecd --- /dev/null +++ b/packages/system/dist/RequestMatcher.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMatcher.js","sourceRoot":"","sources":["../src/RequestMatcher.ts"],"names":[],"mappings":";;;AAEA,SAAgB,kBAAkB,CAAC,EAAc,EAAE,MAAiB;IAClE,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE;QAC3C,OAAO,KAAK,CAAC;KACd;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE;QACnD,OAAO,KAAK,CAAC;KACd;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE;QAC/C,OAAO,KAAK,CAAC;KACd;IACD,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE;QAChD,OAAO,KAAK,CAAC;KACd;IACD,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE;QAChD,OAAO,KAAK,CAAC;KACd;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAjBD,gDAiBC"} \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.d.ts b/packages/system/dist/RequestMerger.d.ts new file mode 100644 index 00000000..47d16a22 --- /dev/null +++ b/packages/system/dist/RequestMerger.d.ts @@ -0,0 +1,24 @@ +import { ReqFilter } from "."; +import { FlatReqFilter } from "./RequestExpander"; +export declare function canMergeFilters(a: FlatReqFilter | ReqFilter, b: FlatReqFilter | ReqFilter): boolean; +export declare function mergeSimilar(filters: Array): Array; +/** + * Simply flatten all filters into one + * @param filters + * @returns + */ +export declare function simpleMerge(filters: Array): ReqFilter; +/** + * Check if a filter includes another filter, as in the bigger filter will include the same results as the samller filter + * @param bigger + * @param smaller + * @returns + */ +export declare function filterIncludes(bigger: ReqFilter, smaller: ReqFilter): boolean; +/** + * Merge expanded flat filters into combined concise filters + * @param all + * @returns + */ +export declare function flatMerge(all: Array): Array; +//# sourceMappingURL=RequestMerger.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.d.ts.map b/packages/system/dist/RequestMerger.d.ts.map new file mode 100644 index 00000000..bdc4e93b --- /dev/null +++ b/packages/system/dist/RequestMerger.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMerger.d.ts","sourceRoot":"","sources":["../src/RequestMerger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQlD,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,SAAS,EAAE,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAWnG;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAmBxE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,aAkBpD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,WAoBnE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAsDrE"} \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.js b/packages/system/dist/RequestMerger.js new file mode 100644 index 00000000..15dfd91c --- /dev/null +++ b/packages/system/dist/RequestMerger.js @@ -0,0 +1,150 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.flatMerge = exports.filterIncludes = exports.simpleMerge = exports.mergeSimilar = exports.canMergeFilters = void 0; +const Util_1 = require("./Util"); +/** + * Keys which can change the entire meaning of the filter outside the array types + */ +const DiscriminatorKeys = ["since", "until", "limit", "search"]; +function canMergeFilters(a, b) { + const aObj = a; + const bObj = b; + for (const key of DiscriminatorKeys) { + if (key in aObj || key in bObj) { + if (aObj[key] !== bObj[key]) { + return false; + } + } + } + return (0, Util_1.distance)(aObj, bObj) <= 1; +} +exports.canMergeFilters = canMergeFilters; +function mergeSimilar(filters) { + console.time("mergeSimilar"); + const ret = []; + const fCopy = [...filters]; + while (fCopy.length > 0) { + const current = fCopy.shift(); + const mergeSet = [current]; + for (let i = 0; i < fCopy.length; i++) { + const f = fCopy[i]; + if (mergeSet.every(v => canMergeFilters(v, f))) { + mergeSet.push(fCopy.splice(i, 1)[0]); + i--; + } + } + ret.push(simpleMerge(mergeSet)); + } + console.timeEnd("mergeSimilar"); + return ret; +} +exports.mergeSimilar = mergeSimilar; +/** + * Simply flatten all filters into one + * @param filters + * @returns + */ +function simpleMerge(filters) { + const result = {}; + filters.forEach(filter => { + Object.entries(filter).forEach(([key, value]) => { + if (Array.isArray(value)) { + if (result[key] === undefined) { + result[key] = [...value]; + } + else { + result[key] = [...new Set([...result[key], ...value])]; + } + } + else { + result[key] = value; + } + }); + }); + return result; +} +exports.simpleMerge = simpleMerge; +/** + * Check if a filter includes another filter, as in the bigger filter will include the same results as the samller filter + * @param bigger + * @param smaller + * @returns + */ +function filterIncludes(bigger, smaller) { + const outside = bigger; + for (const [k, v] of Object.entries(smaller)) { + if (outside[k] === undefined) { + return false; + } + if (Array.isArray(v) && v.some(a => !outside[k].includes(a))) { + return false; + } + if (typeof v === "number") { + if (k === "since" && outside[k] > v) { + return false; + } + if (k === "until" && outside[k] < v) { + return false; + } + // limit cannot be checked and is ignored + } + } + return true; +} +exports.filterIncludes = filterIncludes; +/** + * Merge expanded flat filters into combined concise filters + * @param all + * @returns + */ +function flatMerge(all) { + console.time("flatMerge"); + let ret = []; + // to compute filters which can be merged we need to calucate the distance change between each filter + // then we can merge filters which are exactly 1 change diff from each other + function mergeFiltersInSet(filters) { + const result = {}; + filters.forEach(f => { + const filter = f; + Object.entries(filter).forEach(([key, value]) => { + if (!DiscriminatorKeys.includes(key)) { + if (result[key] === undefined) { + result[key] = [value]; + } + else { + result[key] = [...new Set([...result[key], value])]; + } + } + else { + result[key] = value; + } + }); + }); + return result; + } + // reducer, kinda verbose + while (all.length > 0) { + const currentFilter = all.shift(); + const mergeSet = [currentFilter]; + for (let i = 0; i < all.length; i++) { + const f = all[i]; + if (mergeSet.every(a => canMergeFilters(a, f))) { + mergeSet.push(all.splice(i, 1)[0]); + i--; + } + } + ret.push(mergeFiltersInSet(mergeSet)); + } + while (true) { + const n = mergeSimilar([...ret]); + if (n.length === ret.length) { + break; + } + ret = n; + } + console.timeEnd("flatMerge"); + console.debug(ret); + return ret; +} +exports.flatMerge = flatMerge; +//# sourceMappingURL=RequestMerger.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestMerger.js.map b/packages/system/dist/RequestMerger.js.map new file mode 100644 index 00000000..80069d59 --- /dev/null +++ b/packages/system/dist/RequestMerger.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestMerger.js","sourceRoot":"","sources":["../src/RequestMerger.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.d.ts b/packages/system/dist/RequestSplitter.d.ts new file mode 100644 index 00000000..85e70230 --- /dev/null +++ b/packages/system/dist/RequestSplitter.d.ts @@ -0,0 +1,7 @@ +import { ReqFilter } from "."; +export declare function diffFilters(prev: Array, next: Array): { + added: ReqFilter[]; + removed: ReqFilter[]; + changed: boolean; +}; +//# sourceMappingURL=RequestSplitter.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.d.ts.map b/packages/system/dist/RequestSplitter.d.ts.map new file mode 100644 index 00000000..ad0a50ef --- /dev/null +++ b/packages/system/dist/RequestSplitter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestSplitter.d.ts","sourceRoot":"","sources":["../src/RequestSplitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC;AAK9B,wBAAgB,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;;;;EAYzE"} \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.js b/packages/system/dist/RequestSplitter.js new file mode 100644 index 00000000..13488b3b --- /dev/null +++ b/packages/system/dist/RequestSplitter.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.diffFilters = void 0; +const Util_1 = require("./Util"); +const RequestExpander_1 = require("./RequestExpander"); +const RequestMerger_1 = require("./RequestMerger"); +function diffFilters(prev, next) { + const prevExpanded = prev.flatMap(RequestExpander_1.expandFilter); + const nextExpanded = next.flatMap(RequestExpander_1.expandFilter); + const added = (0, RequestMerger_1.flatMerge)(nextExpanded.filter(a => !prevExpanded.some(b => (0, Util_1.deepEqual)(a, b)))); + const removed = (0, RequestMerger_1.flatMerge)(prevExpanded.filter(a => !nextExpanded.some(b => (0, Util_1.deepEqual)(a, b)))); + return { + added, + removed, + changed: added.length > 0 || removed.length > 0, + }; +} +exports.diffFilters = diffFilters; +//# sourceMappingURL=RequestSplitter.js.map \ No newline at end of file diff --git a/packages/system/dist/RequestSplitter.js.map b/packages/system/dist/RequestSplitter.js.map new file mode 100644 index 00000000..71499c0e --- /dev/null +++ b/packages/system/dist/RequestSplitter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"RequestSplitter.js","sourceRoot":"","sources":["../src/RequestSplitter.ts"],"names":[],"mappings":";;;AACA,iCAAmC;AACnC,uDAAiD;AACjD,mDAA4C;AAE5C,SAAgB,WAAW,CAAC,IAAsB,EAAE,IAAsB;IACxE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,8BAAY,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,8BAAY,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAG,IAAA,yBAAS,EAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,gBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAG,IAAA,yBAAS,EAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,gBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9F,OAAO;QACL,KAAK;QACL,OAAO;QACP,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;KAChD,CAAC;AACJ,CAAC;AAZD,kCAYC"} \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.d.ts b/packages/system/dist/SystemWorker.d.ts new file mode 100644 index 00000000..f9224e50 --- /dev/null +++ b/packages/system/dist/SystemWorker.d.ts @@ -0,0 +1,22 @@ +import { SystemSnapshot, SystemInterface } from "."; +import { AuthHandler, ConnectionStateSnapshot, RelaySettings } from "./Connection"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent } from "./Nostr"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { RequestBuilder } from "./RequestBuilder"; +export declare class SystemWorker extends ExternalStore implements SystemInterface { + #private; + constructor(); + HandleAuth?: AuthHandler; + get Sockets(): ConnectionStateSnapshot[]; + Query(type: new () => T, req: RequestBuilder | null): Query | undefined; + CancelQuery(sub: string): void; + GetQuery(sub: string): Query | undefined; + ConnectToRelay(address: string, options: RelaySettings): Promise; + DisconnectRelay(address: string): void; + BroadcastEvent(ev: NostrEvent): void; + WriteOnceToRelay(relay: string, ev: NostrEvent): Promise; + takeSnapshot(): SystemSnapshot; +} +//# sourceMappingURL=SystemWorker.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.d.ts.map b/packages/system/dist/SystemWorker.d.ts.map new file mode 100644 index 00000000..d6581294 --- /dev/null +++ b/packages/system/dist/SystemWorker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"SystemWorker.d.ts","sourceRoot":"","sources":["../src/SystemWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,GAAG,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,YAAa,SAAQ,aAAa,CAAC,cAAc,CAAE,YAAW,eAAe;;;IAcxF,UAAU,CAAC,EAAE,WAAW,CAAC;IAEzB,IAAI,OAAO,IAAI,uBAAuB,EAAE,CAEvC;IAED,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS;IAI5F,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI9B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIxC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAItC,cAAc,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAIpC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,YAAY,IAAI,cAAc;CAO/B"} \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.js b/packages/system/dist/SystemWorker.js new file mode 100644 index 00000000..703bd8e1 --- /dev/null +++ b/packages/system/dist/SystemWorker.js @@ -0,0 +1,66 @@ +"use strict"; +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _SystemWorker_instances, _SystemWorker_port, _SystemWorker_onMessage; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SystemWorker = void 0; +const ExternalStore_1 = __importDefault(require("./ExternalStore")); +class SystemWorker extends ExternalStore_1.default { + constructor() { + super(); + _SystemWorker_instances.add(this); + _SystemWorker_port.set(this, void 0); + if ("SharedWorker" in window) { + const worker = new SharedWorker("/system.js"); + __classPrivateFieldSet(this, _SystemWorker_port, worker.port, "f"); + __classPrivateFieldGet(this, _SystemWorker_port, "f").onmessage = m => __classPrivateFieldGet(this, _SystemWorker_instances, "m", _SystemWorker_onMessage).call(this, m); + } + else { + throw new Error("SharedWorker is not supported"); + } + } + get Sockets() { + throw new Error("Method not implemented."); + } + Query(type, req) { + throw new Error("Method not implemented."); + } + CancelQuery(sub) { + throw new Error("Method not implemented."); + } + GetQuery(sub) { + throw new Error("Method not implemented."); + } + ConnectToRelay(address, options) { + throw new Error("Method not implemented."); + } + DisconnectRelay(address) { + throw new Error("Method not implemented."); + } + BroadcastEvent(ev) { + throw new Error("Method not implemented."); + } + WriteOnceToRelay(relay, ev) { + throw new Error("Method not implemented."); + } + takeSnapshot() { + throw new Error("Method not implemented."); + } +} +exports.SystemWorker = SystemWorker; +_SystemWorker_port = new WeakMap(), _SystemWorker_instances = new WeakSet(), _SystemWorker_onMessage = function _SystemWorker_onMessage(e) { + console.debug(e); +}; +//# sourceMappingURL=SystemWorker.js.map \ No newline at end of file diff --git a/packages/system/dist/SystemWorker.js.map b/packages/system/dist/SystemWorker.js.map new file mode 100644 index 00000000..9b87a7f2 --- /dev/null +++ b/packages/system/dist/SystemWorker.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SystemWorker.js","sourceRoot":"","sources":["../src/SystemWorker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAEA,oEAA4C;AAM5C,MAAa,YAAa,SAAQ,uBAA6B;IAG7D;QACE,KAAK,EAAE,CAAC;;QAHV,qCAAmB;QAIjB,IAAI,cAAc,IAAI,MAAM,EAAE;YAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;YAC9C,uBAAA,IAAI,sBAAS,MAAM,CAAC,IAAI,MAAA,CAAC;YACzB,uBAAA,IAAI,0BAAM,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,uBAAA,IAAI,wDAAW,MAAf,IAAI,EAAY,CAAC,CAAC,CAAC;SAChD;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;SAClD;IACH,CAAC;IAID,IAAI,OAAO;QACT,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAsB,IAAiB,EAAE,GAA0B;QACtE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,WAAW,CAAC,GAAW;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,OAAe,EAAE,OAAsB;QACpD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,eAAe,CAAC,OAAe;QAC7B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,EAAc;QAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,gBAAgB,CAAC,KAAa,EAAE,EAAc;QAC5C,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,YAAY;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CAKF;AAvDD,oCAuDC;wIAHY,CAAoB;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/Tag.d.ts b/packages/system/dist/Tag.d.ts new file mode 100644 index 00000000..d94498cb --- /dev/null +++ b/packages/system/dist/Tag.d.ts @@ -0,0 +1,18 @@ +import { HexKey, u256 } from "./Nostr"; +export default class Tag { + Original: string[]; + Key: string; + Event?: u256; + PubKey?: HexKey; + Relay?: string; + Marker?: string; + Hashtag?: string; + DTag?: string; + ATag?: string; + Index: number; + Invalid: boolean; + LNURL?: string; + constructor(tag: string[], index: number); + ToObject(): string[] | null; +} +//# sourceMappingURL=Tag.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Tag.d.ts.map b/packages/system/dist/Tag.d.ts.map new file mode 100644 index 00000000..a961ec79 --- /dev/null +++ b/packages/system/dist/Tag.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Tag.d.ts","sourceRoot":"","sources":["../src/Tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGvC,MAAM,CAAC,OAAO,OAAO,GAAG;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEH,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM;IAgDxC,QAAQ,IAAI,MAAM,EAAE,GAAG,IAAI;CAsB5B"} \ No newline at end of file diff --git a/packages/system/dist/Tag.js b/packages/system/dist/Tag.js new file mode 100644 index 00000000..3a0b281f --- /dev/null +++ b/packages/system/dist/Tag.js @@ -0,0 +1,75 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const Util_1 = require("./Util"); +class Tag { + constructor(tag, index) { + this.Original = tag; + this.Key = tag[0]; + this.Index = index; + this.Invalid = false; + switch (this.Key) { + case "e": { + // ["e", , , ] + this.Event = tag[1]; + this.Relay = tag.length > 2 ? tag[2] : undefined; + this.Marker = tag.length > 3 ? tag[3] : undefined; + if (!this.Event) { + this.Invalid = true; + } + break; + } + case "p": { + // ["p", ] + this.PubKey = tag[1]; + if (!this.PubKey) { + this.Invalid = true; + } + break; + } + case "d": { + this.DTag = tag[1]; + break; + } + case "a": { + this.ATag = tag[1]; + break; + } + case "t": { + this.Hashtag = tag[1]; + break; + } + case "delegation": { + this.PubKey = tag[1]; + break; + } + case "zap": { + this.LNURL = tag[1]; + break; + } + } + } + ToObject() { + switch (this.Key) { + case "e": { + let ret = ["e", this.Event, this.Relay, this.Marker]; + const trimEnd = ret.reverse().findIndex(a => a !== undefined); + ret = ret.reverse().slice(0, ret.length - trimEnd); + return ret; + } + case "p": { + return this.PubKey ? ["p", this.PubKey] : null; + } + case "t": { + return ["t", (0, Util_1.unwrap)(this.Hashtag)]; + } + case "d": { + return ["d", (0, Util_1.unwrap)(this.DTag)]; + } + default: { + return this.Original; + } + } + } +} +exports.default = Tag; +//# sourceMappingURL=Tag.js.map \ No newline at end of file diff --git a/packages/system/dist/Tag.js.map b/packages/system/dist/Tag.js.map new file mode 100644 index 00000000..1e6461c5 --- /dev/null +++ b/packages/system/dist/Tag.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Tag.js","sourceRoot":"","sources":["../src/Tag.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/Util.d.ts b/packages/system/dist/Util.d.ts new file mode 100644 index 00000000..b62acff4 --- /dev/null +++ b/packages/system/dist/Util.d.ts @@ -0,0 +1,23 @@ +import { NostrEvent, u256 } from "./Nostr"; +export declare function unwrap(v: T | undefined | null): T; +/** + * Convert hex to bech32 + */ +export declare function hexToBech32(hrp: string, hex?: string): string; +export declare function sanitizeRelayUrl(url: string): string | undefined; +export declare function unixNow(): number; +export declare function unixNowMs(): number; +export declare function deepEqual(x: any, y: any): boolean; +/** + * Compute the "distance" between two objects by comparing their difference in properties + * Missing/Added keys result in +10 distance + * This is not recursive + */ +export declare function distance(a: any, b: any): number; +export declare function dedupe(v: Array): T[]; +export declare function appendDedupe(a?: Array, b?: Array): T[]; +export declare function findTag(e: NostrEvent, tag: string): string | undefined; +export declare const sha256: (str: string | Uint8Array) => u256; +export declare function getPublicKey(privKey: string): string; +export declare function bech32ToHex(str: string): string; +//# sourceMappingURL=Util.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/Util.d.ts.map b/packages/system/dist/Util.d.ts.map new file mode 100644 index 00000000..e7c9a5a5 --- /dev/null +++ b/packages/system/dist/Util.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Util.d.ts","sourceRoot":"","sources":["../src/Util.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE3C,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,CAKpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,UAYpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,sBAM3C;AAED,wBAAgB,OAAO,WAEtB;AAED,wBAAgB,SAAS,WAExB;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAQjD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CA2B/C;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,OAEpC;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,OAEzD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,sBAKjD;AAED,eAAO,MAAM,MAAM,QAAS,MAAM,GAAG,UAAU,KAAG,IAEjD,CAAA;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,UAE3C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,UAQtC"} \ No newline at end of file diff --git a/packages/system/dist/Util.js b/packages/system/dist/Util.js new file mode 100644 index 00000000..92f0d069 --- /dev/null +++ b/packages/system/dist/Util.js @@ -0,0 +1,148 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bech32ToHex = exports.getPublicKey = exports.sha256 = exports.findTag = exports.appendDedupe = exports.dedupe = exports.distance = exports.deepEqual = exports.unixNowMs = exports.unixNow = exports.sanitizeRelayUrl = exports.hexToBech32 = exports.unwrap = void 0; +const utils = __importStar(require("@noble/curves/abstract/utils")); +const secp = __importStar(require("@noble/curves/secp256k1")); +const sha256_1 = require("@noble/hashes/sha256"); +const bech32_1 = require("bech32"); +function unwrap(v) { + if (v === undefined || v === null) { + throw new Error("missing value"); + } + return v; +} +exports.unwrap = unwrap; +/** + * Convert hex to bech32 + */ +function hexToBech32(hrp, hex) { + if (typeof hex !== "string" || hex.length === 0 || hex.length % 2 !== 0) { + return ""; + } + try { + const buf = utils.hexToBytes(hex); + return bech32_1.bech32.encode(hrp, bech32_1.bech32.toWords(buf)); + } + catch (e) { + console.warn("Invalid hex", hex, e); + return ""; + } +} +exports.hexToBech32 = hexToBech32; +function sanitizeRelayUrl(url) { + try { + return new URL(url).toString(); + } + catch { + // ignore + } +} +exports.sanitizeRelayUrl = sanitizeRelayUrl; +function unixNow() { + return Math.floor(unixNowMs() / 1000); +} +exports.unixNow = unixNow; +function unixNowMs() { + return new Date().getTime(); +} +exports.unixNowMs = unixNowMs; +function deepEqual(x, y) { + const ok = Object.keys, tx = typeof x, ty = typeof y; + return x && y && tx === "object" && tx === ty + ? ok(x).length === ok(y).length && ok(x).every(key => deepEqual(x[key], y[key])) + : x === y; +} +exports.deepEqual = deepEqual; +/** + * Compute the "distance" between two objects by comparing their difference in properties + * Missing/Added keys result in +10 distance + * This is not recursive + */ +function distance(a, b) { + const keys1 = Object.keys(a); + const keys2 = Object.keys(b); + const maxKeys = keys1.length > keys2.length ? keys1 : keys2; + let distance = 0; + for (const key of maxKeys) { + if (key in a && key in b) { + if (Array.isArray(a[key]) && Array.isArray(b[key])) { + const aa = a[key]; + const bb = b[key]; + if (aa.length === bb.length) { + if (aa.some(v => !bb.includes(v))) { + distance++; + } + } + else { + distance++; + } + } + else if (a[key] !== b[key]) { + distance++; + } + } + else { + distance += 10; + } + } + return distance; +} +exports.distance = distance; +function dedupe(v) { + return [...new Set(v)]; +} +exports.dedupe = dedupe; +function appendDedupe(a, b) { + return dedupe([...(a ?? []), ...(b ?? [])]); +} +exports.appendDedupe = appendDedupe; +function findTag(e, tag) { + const maybeTag = e.tags.find(evTag => { + return evTag[0] === tag; + }); + return maybeTag && maybeTag[1]; +} +exports.findTag = findTag; +const sha256 = (str) => { + return utils.bytesToHex((0, sha256_1.sha256)(str)); +}; +exports.sha256 = sha256; +function getPublicKey(privKey) { + return utils.bytesToHex(secp.schnorr.getPublicKey(privKey)); +} +exports.getPublicKey = getPublicKey; +function bech32ToHex(str) { + try { + const nKey = bech32_1.bech32.decode(str, 1000); + const buff = bech32_1.bech32.fromWords(nKey.words); + return utils.bytesToHex(Uint8Array.from(buff)); + } + catch (e) { + return str; + } +} +exports.bech32ToHex = bech32ToHex; +//# sourceMappingURL=Util.js.map \ No newline at end of file diff --git a/packages/system/dist/Util.js.map b/packages/system/dist/Util.js.map new file mode 100644 index 00000000..9846635c --- /dev/null +++ b/packages/system/dist/Util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Util.js","sourceRoot":"","sources":["../src/Util.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.d.ts b/packages/system/dist/WorkQueue.d.ts new file mode 100644 index 00000000..3b1df622 --- /dev/null +++ b/packages/system/dist/WorkQueue.d.ts @@ -0,0 +1,8 @@ +export interface WorkQueueItem { + next: () => Promise; + resolve(v: unknown): void; + reject(e: unknown): void; +} +export declare function processWorkQueue(queue?: Array, queueDelay?: number): Promise; +export declare const barrierQueue: (queue: Array, then: () => Promise) => Promise; +//# sourceMappingURL=WorkQueue.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.d.ts.map b/packages/system/dist/WorkQueue.d.ts.map new file mode 100644 index 00000000..2f91432e --- /dev/null +++ b/packages/system/dist/WorkQueue.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WorkQueue.d.ts","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,EAAE,UAAU,SAAM,iBAapF;AAED,eAAO,MAAM,YAAY,aAAoB,MAAM,aAAa,CAAC,uCAQhE,CAAC"} \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.js b/packages/system/dist/WorkQueue.js new file mode 100644 index 00000000..b9d0b0d6 --- /dev/null +++ b/packages/system/dist/WorkQueue.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.barrierQueue = exports.processWorkQueue = void 0; +async function processWorkQueue(queue, queueDelay = 200) { + while (queue && queue.length > 0) { + const v = queue.shift(); + if (v) { + try { + const ret = await v.next(); + v.resolve(ret); + } + catch (e) { + v.reject(e); + } + } + } + setTimeout(() => processWorkQueue(queue, queueDelay), queueDelay); +} +exports.processWorkQueue = processWorkQueue; +const barrierQueue = async (queue, then) => { + return new Promise((resolve, reject) => { + queue.push({ + next: then, + resolve, + reject, + }); + }); +}; +exports.barrierQueue = barrierQueue; +//# sourceMappingURL=WorkQueue.js.map \ No newline at end of file diff --git a/packages/system/dist/WorkQueue.js.map b/packages/system/dist/WorkQueue.js.map new file mode 100644 index 00000000..8f34b037 --- /dev/null +++ b/packages/system/dist/WorkQueue.js.map @@ -0,0 +1 @@ +{"version":3,"file":"WorkQueue.js","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";;;AAMO,KAAK,UAAU,gBAAgB,CAAC,KAA4B,EAAE,UAAU,GAAG,GAAG;IACnF,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QAChC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,EAAE;YACL,IAAI;gBACF,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;aAChB;YAAC,OAAO,CAAC,EAAE;gBACV,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aACb;SACF;KACF;IACD,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;AACpE,CAAC;AAbD,4CAaC;AAEM,MAAM,YAAY,GAAG,KAAK,EAAK,KAA2B,EAAE,IAAsB,EAAc,EAAE;IACvG,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,IAAI;YACV,OAAO;YACP,MAAM;SACP,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AARW,QAAA,YAAY,gBAQvB"} \ No newline at end of file diff --git a/packages/system/dist/cache/index.d.ts b/packages/system/dist/cache/index.d.ts new file mode 100644 index 00000000..f8fc473f --- /dev/null +++ b/packages/system/dist/cache/index.d.ts @@ -0,0 +1,48 @@ +import { HexKey, NostrEvent, UserMetadata } from ".."; +export interface MetadataCache extends UserMetadata { + /** + * When the object was saved in cache + */ + loaded: number; + /** + * When the source metadata event was created + */ + created: number; + /** + * The pubkey of the owner of this metadata + */ + pubkey: HexKey; + /** + * The bech32 encoded pubkey + */ + npub: string; + /** + * Pubkey of zapper service + */ + zapService?: HexKey; + /** + * If the nip05 is valid for this user + */ + isNostrAddressValid: boolean; +} +export declare function mapEventToProfile(ev: NostrEvent): MetadataCache | undefined; +export interface CacheStore { + preload(): Promise; + getFromCache(key?: string): T | undefined; + get(key?: string): Promise; + bulkGet(keys: Array): Promise>; + set(obj: T): Promise; + bulkSet(obj: Array): Promise; + update(m: TCachedWithCreated): Promise<"new" | "updated" | "refresh" | "no_change">; + /** + * Loads a list of rows from disk cache + * @param keys List of ids to load + * @returns Keys that do not exist on disk cache + */ + buffer(keys: Array): Promise>; + clear(): Promise; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/cache/index.d.ts.map b/packages/system/dist/cache/index.d.ts.map new file mode 100644 index 00000000..65d321a7 --- /dev/null +++ b/packages/system/dist/cache/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAGtD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,6BAa/C;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAC1C,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,kBAAkB,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC,CAAA;IAEvJ;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"} \ No newline at end of file diff --git a/packages/system/dist/cache/index.js b/packages/system/dist/cache/index.js new file mode 100644 index 00000000..f21265bd --- /dev/null +++ b/packages/system/dist/cache/index.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.mapEventToProfile = void 0; +const Util_1 = require("../Util"); +function mapEventToProfile(ev) { + try { + const data = JSON.parse(ev.content); + return { + ...data, + pubkey: ev.pubkey, + npub: (0, Util_1.hexToBech32)("npub", ev.pubkey), + created: ev.created_at, + loaded: (0, Util_1.unixNowMs)(), + }; + } + catch (e) { + console.error("Failed to parse JSON", ev, e); + } +} +exports.mapEventToProfile = mapEventToProfile; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/system/dist/cache/index.js.map b/packages/system/dist/cache/index.js.map new file mode 100644 index 00000000..6660f61b --- /dev/null +++ b/packages/system/dist/cache/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":";;;AACA,kCAAiD;AAkCjD,SAAgB,iBAAiB,CAAC,EAAc;IAC9C,IAAI;QACF,MAAM,IAAI,GAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAClD,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,IAAI,EAAE,IAAA,kBAAW,EAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC;YACpC,OAAO,EAAE,EAAE,CAAC,UAAU;YACtB,MAAM,EAAE,IAAA,gBAAS,GAAE;SACH,CAAC;KACpB;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;KAC9C;AACH,CAAC;AAbD,8CAaC"} \ No newline at end of file diff --git a/packages/system/dist/index.d.ts b/packages/system/dist/index.d.ts new file mode 100644 index 00000000..08c37550 --- /dev/null +++ b/packages/system/dist/index.d.ts @@ -0,0 +1,44 @@ +import { AuthHandler, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { RequestBuilder } from "./RequestBuilder"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { NostrEvent, ReqFilter } from "./Nostr"; +export * from "./NostrSystem"; +export { default as EventKind } from "./EventKind"; +export * from "./Nostr"; +export * from "./Links"; +export { default as Tag } from "./Tag"; +export * from "./Nips"; +export * from "./RelayInfo"; +export * from "./EventExt"; +export * from "./Connection"; +export * from "./NoteCollection"; +export * from "./RequestBuilder"; +export * from "./EventPublisher"; +export * from "./EventBuilder"; +export * from "./NostrLink"; +export * from "./cache"; +export * from "./ProfileCache"; +export interface SystemInterface { + /** + * Handler function for NIP-42 + */ + HandleAuth?: AuthHandler; + get Sockets(): Array; + GetQuery(id: string): Query | undefined; + Query(type: { + new (): T; + }, req: RequestBuilder | null): Query | undefined; + ConnectToRelay(address: string, options: RelaySettings): Promise; + DisconnectRelay(address: string): void; + BroadcastEvent(ev: NostrEvent): void; + WriteOnceToRelay(relay: string, ev: NostrEvent): Promise; +} +export interface SystemSnapshot { + queries: Array<{ + id: string; + filters: Array; + subFilters: Array; + }>; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/system/dist/index.d.ts.map b/packages/system/dist/index.d.ts.map new file mode 100644 index 00000000..d9004955 --- /dev/null +++ b/packages/system/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEhD,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAC;AACvC,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,IAAI,OAAO,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,EAAE;QAAE,QAAO,CAAC,CAAA;KAAE,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,CAAC;IAC9F,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,cAAc,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,CAAC;IACrC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1B,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;KAC9B,CAAC,CAAC;CACJ"} \ No newline at end of file diff --git a/packages/system/dist/index.js b/packages/system/dist/index.js new file mode 100644 index 00000000..9e8c83e3 --- /dev/null +++ b/packages/system/dist/index.js @@ -0,0 +1,39 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Tag = exports.EventKind = void 0; +__exportStar(require("./NostrSystem"), exports); +var EventKind_1 = require("./EventKind"); +Object.defineProperty(exports, "EventKind", { enumerable: true, get: function () { return __importDefault(EventKind_1).default; } }); +__exportStar(require("./Nostr"), exports); +__exportStar(require("./Links"), exports); +var Tag_1 = require("./Tag"); +Object.defineProperty(exports, "Tag", { enumerable: true, get: function () { return __importDefault(Tag_1).default; } }); +__exportStar(require("./Nips"), exports); +__exportStar(require("./RelayInfo"), exports); +__exportStar(require("./EventExt"), exports); +__exportStar(require("./Connection"), exports); +__exportStar(require("./NoteCollection"), exports); +__exportStar(require("./RequestBuilder"), exports); +__exportStar(require("./EventPublisher"), exports); +__exportStar(require("./EventBuilder"), exports); +__exportStar(require("./NostrLink"), exports); +__exportStar(require("./cache"), exports); +__exportStar(require("./ProfileCache"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/system/dist/index.js.map b/packages/system/dist/index.js.map new file mode 100644 index 00000000..a0e12b3a --- /dev/null +++ b/packages/system/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAMA,gDAA8B;AAC9B,yCAAmD;AAA1C,uHAAA,OAAO,OAAa;AAC7B,0CAAwB;AACxB,0CAAwB;AACxB,6BAAuC;AAA9B,2GAAA,OAAO,OAAO;AACvB,yCAAuB;AACvB,8CAA4B;AAC5B,6CAA2B;AAC3B,+CAA6B;AAC7B,mDAAiC;AACjC,mDAAiC;AACjC,mDAAiC;AACjC,iDAA+B;AAC/B,8CAA4B;AAC5B,0CAAwB;AACxB,iDAA+B"} \ No newline at end of file diff --git a/packages/system/jest.config.js b/packages/system/jest.config.js new file mode 100644 index 00000000..1ccd5800 --- /dev/null +++ b/packages/system/jest.config.js @@ -0,0 +1,9 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + bail: true, + preset: "ts-jest", + testEnvironment: "jsdom", + roots: ["src"], + moduleDirectories: ["src"], + setupFiles: ["./tests/setupTests.ts"], +}; diff --git a/packages/system/package.json b/packages/system/package.json new file mode 100644 index 00000000..ecdd59f6 --- /dev/null +++ b/packages/system/package.json @@ -0,0 +1,29 @@ +{ + "name": "@snort/system", + "version": "1.0.0", + "description": "Snort nostr system package", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "repository": "https://git.v0l.io/Kieran/snort", + "author": "Kieran", + "license": "GPLv3", + "scripts": { + "build": "rm -rf dist && tsc", + "test": "jest" + }, + "devDependencies": { + "@jest/globals": "^29.5.0", + "@types/jest": "^29.5.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "ts-jest": "^29.1.0", + "typescript": "^5.0.4" + }, + "dependencies": { + "@noble/curves": "^1.0.0", + "@protobufjs/base64": "^1.1.2", + "bech32": "^2.0.0", + "debug": "^4.3.4", + "uuid": "^9.0.0" + } +} diff --git a/packages/system/snort-system-1.0.0.tgz b/packages/system/snort-system-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3384474ebdb187e6e3ff3ba8e0f4713a867d1303 GIT binary patch literal 56011 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 literal 0 HcmV?d00001 diff --git a/packages/app/src/System/Connection.ts b/packages/system/src/Connection.ts similarity index 99% rename from packages/app/src/System/Connection.ts rename to packages/system/src/Connection.ts index 109410e6..c4e11052 100644 --- a/packages/app/src/System/Connection.ts +++ b/packages/system/src/Connection.ts @@ -5,7 +5,7 @@ import { ConnectionStats } from "./ConnectionStats"; import { NostrEvent, ReqCommand, TaggedRawEvent, u256 } from "./Nostr"; import { RelayInfo } from "./RelayInfo"; import { unwrap } from "./Util"; -import ExternalStore from "ExternalStore"; +import ExternalStore from "./ExternalStore"; export type AuthHandler = (challenge: string, relay: string) => Promise; diff --git a/packages/app/src/System/ConnectionStats.ts b/packages/system/src/ConnectionStats.ts similarity index 100% rename from packages/app/src/System/ConnectionStats.ts rename to packages/system/src/ConnectionStats.ts diff --git a/packages/system/src/Const.ts b/packages/system/src/Const.ts new file mode 100644 index 00000000..f2e94a65 --- /dev/null +++ b/packages/system/src/Const.ts @@ -0,0 +1,16 @@ +/** + * Websocket re-connect timeout + */ +export const DefaultConnectTimeout = 2000; + +/** + * Hashtag regex + */ +// eslint-disable-next-line no-useless-escape +export const HashtagRegex = /(#[^\s!@#$%^&*()=+.\/,\[{\]};:'"?><]+)/g; + + +/** + * How long profile cache should be considered valid for + */ + export const ProfileCacheExpire = 1_000 * 60 * 60 * 6; \ No newline at end of file diff --git a/packages/app/src/System/EventBuilder.ts b/packages/system/src/EventBuilder.ts similarity index 91% rename from packages/app/src/System/EventBuilder.ts rename to packages/system/src/EventBuilder.ts index 73a285e1..d59bd647 100644 --- a/packages/app/src/System/EventBuilder.ts +++ b/packages/system/src/EventBuilder.ts @@ -1,7 +1,8 @@ -import { EventKind, HexKey, NostrPrefix, NostrEvent } from "System"; -import { HashtagRegex } from "Const"; -import { getPublicKey, parseNostrLink, unixNow } from "SnortUtils"; +import { EventKind, HexKey, NostrPrefix, NostrEvent } from "."; +import { HashtagRegex } from "./Const"; +import { getPublicKey, unixNow } from "./Util"; import { EventExt } from "./EventExt"; +import { parseNostrLink } from "./NostrLink"; export class EventBuilder { #kind?: EventKind; diff --git a/packages/app/src/System/EventExt.ts b/packages/system/src/EventExt.ts similarity index 92% rename from packages/app/src/System/EventExt.ts rename to packages/system/src/EventExt.ts index ebbf0f15..4df025ad 100644 --- a/packages/app/src/System/EventExt.ts +++ b/packages/system/src/EventExt.ts @@ -1,8 +1,8 @@ import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; -import { EventKind, HexKey, NostrEvent, Tag } from "System"; +import { EventKind, HexKey, NostrEvent, Tag } from "."; import base64 from "@protobufjs/base64"; -import { sha256, unixNow } from "SnortUtils"; +import { sha256, unixNow } from "./Util"; export interface Thread { root?: Tag; @@ -18,6 +18,7 @@ export abstract class EventExt { static getRootPubKey(e: NostrEvent): HexKey { const delegation = e.tags.find(a => a[0] === "delegation"); if (delegation?.[1]) { + // todo: verify sig return delegation[1]; } return e.pubkey; @@ -26,12 +27,12 @@ export abstract class EventExt { /** * Sign this message with a private key */ - static async sign(e: NostrEvent, key: HexKey) { + static sign(e: NostrEvent, key: HexKey) { e.id = this.createId(e); - const sig = await secp.schnorr.sign(e.id, key); + const sig = secp.schnorr.sign(e.id, key); e.sig = utils.bytesToHex(sig); - if (!(await secp.schnorr.verify(e.sig, e.id, e.pubkey))) { + if (!(secp.schnorr.verify(e.sig, e.id, e.pubkey))) { throw new Error("Signing failed"); } } @@ -40,9 +41,9 @@ export abstract class EventExt { * Check the signature of this message * @returns True if valid signature */ - static async verify(e: NostrEvent) { + static verify(e: NostrEvent) { const id = this.createId(e); - const result = await secp.schnorr.verify(e.sig, id, e.pubkey); + const result = secp.schnorr.verify(e.sig, id, e.pubkey); return result; } diff --git a/packages/app/src/System/EventKind.ts b/packages/system/src/EventKind.ts similarity index 100% rename from packages/app/src/System/EventKind.ts rename to packages/system/src/EventKind.ts diff --git a/packages/app/src/System/EventPublisher.ts b/packages/system/src/EventPublisher.ts similarity index 93% rename from packages/app/src/System/EventPublisher.ts rename to packages/system/src/EventPublisher.ts index 8aa29bad..b452bf48 100644 --- a/packages/app/src/System/EventPublisher.ts +++ b/packages/system/src/EventPublisher.ts @@ -11,13 +11,12 @@ import { TaggedRawEvent, u256, UserMetadata, -} from "System"; +} from "."; -import { DefaultRelays } from "Const"; -import { unwrap } from "SnortUtils"; +import { unwrap } from "./Util"; import { EventBuilder } from "./EventBuilder"; import { EventExt } from "./EventExt"; -import { barrierQueue, processWorkQueue, WorkQueueItem } from "WorkQueue"; +import { barrierQueue, processWorkQueue, WorkQueueItem } from "./WorkQueue"; const Nip7Queue: Array = []; processWorkQueue(Nip7Queue); @@ -118,17 +117,6 @@ export class EventPublisher { this.#system.BroadcastEvent(ev); } - /** - * Write event to DefaultRelays, this is important for profiles / relay lists to prevent bugs - * If a user removes all the DefaultRelays from their relay list and saves that relay list, - * When they open the site again we wont see that updated relay list and so it will appear to reset back to the previous state - */ - broadcastForBootstrap(ev: NostrEvent) { - for (const [k] of DefaultRelays) { - this.#system.WriteOnceToRelay(k, ev); - } - } - /** * Write event to all given relays. */ diff --git a/packages/system/src/ExternalStore.ts b/packages/system/src/ExternalStore.ts new file mode 100644 index 00000000..4b1dedea --- /dev/null +++ b/packages/system/src/ExternalStore.ts @@ -0,0 +1,41 @@ +type HookFn = (e?: TSnapshot) => void; + +interface HookFilter { + fn: HookFn; +} + +/** + * Simple React hookable store with manual change notifications + */ +export default abstract class ExternalStore { + #hooks: Array> = []; + #snapshot: Readonly = {} as Readonly; + #changed = true; + + hook(fn: HookFn) { + this.#hooks.push({ + fn, + }); + return () => { + const idx = this.#hooks.findIndex(a => a.fn === fn); + if (idx >= 0) { + this.#hooks.splice(idx, 1); + } + }; + } + + snapshot() { + if (this.#changed) { + this.#snapshot = this.takeSnapshot(); + this.#changed = false; + } + return this.#snapshot; + } + + protected notifyChange(sn?: TSnapshot) { + this.#changed = true; + this.#hooks.forEach(h => h.fn(sn)); + } + + abstract takeSnapshot(): TSnapshot; +} diff --git a/packages/app/src/System/GossipModel.ts b/packages/system/src/GossipModel.ts similarity index 96% rename from packages/app/src/System/GossipModel.ts rename to packages/system/src/GossipModel.ts index 5cdd2d41..07f8817e 100644 --- a/packages/app/src/System/GossipModel.ts +++ b/packages/system/src/GossipModel.ts @@ -1,5 +1,5 @@ -import { FullRelaySettings, ReqFilter } from "System"; -import { unwrap } from "SnortUtils"; +import { FullRelaySettings, ReqFilter } from "."; +import { unwrap } from "./Util"; import debug from "debug"; const PickNRelays = 2; diff --git a/packages/app/src/System/Links.ts b/packages/system/src/Links.ts similarity index 100% rename from packages/app/src/System/Links.ts rename to packages/system/src/Links.ts diff --git a/packages/app/src/System/Nips.ts b/packages/system/src/Nips.ts similarity index 100% rename from packages/app/src/System/Nips.ts rename to packages/system/src/Nips.ts diff --git a/packages/app/src/System/Nostr.ts b/packages/system/src/Nostr.ts similarity index 100% rename from packages/app/src/System/Nostr.ts rename to packages/system/src/Nostr.ts diff --git a/packages/system/src/NostrLink.ts b/packages/system/src/NostrLink.ts new file mode 100644 index 00000000..cb663b3b --- /dev/null +++ b/packages/system/src/NostrLink.ts @@ -0,0 +1,110 @@ +import { bech32ToHex, hexToBech32 } from "./Util"; +import { NostrPrefix, decodeTLV, TLVEntryType } from "."; + +export interface NostrLink { + type: NostrPrefix; + id: string; + kind?: number; + author?: string; + relays?: Array; + encode(): string; + } + + export function validateNostrLink(link: string): boolean { + try { + const parsedLink = parseNostrLink(link); + if (!parsedLink) { + return false; + } + if (parsedLink.type === NostrPrefix.PublicKey || parsedLink.type === NostrPrefix.Note) { + return parsedLink.id.length === 64; + } + + return true; + } catch { + return false; + } + } + + export function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink | undefined { + try { + return parseNostrLink(link, prefixHint); + } catch { + return undefined; + } + } + + export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink { + const entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link; + + const isPrefix = (prefix: NostrPrefix) => { + return entity.startsWith(prefix); + }; + + if (isPrefix(NostrPrefix.PublicKey)) { + const id = bech32ToHex(entity); + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.PublicKey, + id: id, + encode: () => hexToBech32(NostrPrefix.PublicKey, id), + }; + } else if (isPrefix(NostrPrefix.Note)) { + const id = bech32ToHex(entity); + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Note, + id: id, + encode: () => hexToBech32(NostrPrefix.Note, id), + }; + } else if (isPrefix(NostrPrefix.Profile) || isPrefix(NostrPrefix.Event) || isPrefix(NostrPrefix.Address)) { + const decoded = decodeTLV(entity); + + const id = decoded.find(a => a.type === TLVEntryType.Special)?.value as string; + const relays = decoded.filter(a => a.type === TLVEntryType.Relay).map(a => a.value as string); + const author = decoded.find(a => a.type === TLVEntryType.Author)?.value as string; + const kind = decoded.find(a => a.type === TLVEntryType.Kind)?.value as number; + + const encode = () => { + return entity; // return original + }; + if (isPrefix(NostrPrefix.Profile)) { + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Profile, + id, + relays, + kind, + author, + encode, + }; + } else if (isPrefix(NostrPrefix.Event)) { + if (id.length !== 64) throw new Error("Invalid nostr link, must contain 32 byte id"); + return { + type: NostrPrefix.Event, + id, + relays, + kind, + author, + encode, + }; + } else if (isPrefix(NostrPrefix.Address)) { + return { + type: NostrPrefix.Address, + id, + relays, + kind, + author, + encode, + }; + } + } else if (prefixHint) { + return { + type: prefixHint, + id: link, + encode: () => hexToBech32(prefixHint, link), + }; + } + throw new Error("Invalid nostr link"); + } + \ No newline at end of file diff --git a/packages/app/src/System/NostrSystem.ts b/packages/system/src/NostrSystem.ts similarity index 95% rename from packages/app/src/System/NostrSystem.ts rename to packages/system/src/NostrSystem.ts index a34a641f..c20b96a8 100644 --- a/packages/app/src/System/NostrSystem.ts +++ b/packages/system/src/NostrSystem.ts @@ -1,15 +1,14 @@ import debug from "debug"; -import { v4 as uuid } from "uuid"; -import ExternalStore from "ExternalStore"; -import { NostrEvent, ReqFilter, TaggedRawEvent } from "./Nostr"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent, TaggedRawEvent } from "./Nostr"; import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; -import { Query, QueryBase } from "./Query"; +import { Query } from "./Query"; import { RelayCache } from "./GossipModel"; import { NoteStore } from "./NoteCollection"; import { BuiltRawReqFilter, RequestBuilder } from "./RequestBuilder"; -import { unwrap, sanitizeRelayUrl, unixNowMs } from "./Util"; -import { SystemInterface, SystemSnapshot } from "System"; +import { unwrap, sanitizeRelayUrl } from "./Util"; +import { SystemInterface, SystemSnapshot } from "."; /** * Manages nostr content retrieval system diff --git a/packages/app/src/System/NoteCollection.ts b/packages/system/src/NoteCollection.ts similarity index 98% rename from packages/app/src/System/NoteCollection.ts rename to packages/system/src/NoteCollection.ts index 85974f14..f33e41f7 100644 --- a/packages/app/src/System/NoteCollection.ts +++ b/packages/system/src/NoteCollection.ts @@ -1,5 +1,5 @@ -import { TaggedRawEvent, u256 } from "System"; -import { appendDedupe, findTag } from "SnortUtils"; +import { TaggedRawEvent, u256 } from "."; +import { appendDedupe, findTag } from "./Util"; export interface StoreSnapshot { data: TSnapshot | undefined; diff --git a/packages/app/src/System/ProfileCache.ts b/packages/system/src/ProfileCache.ts similarity index 83% rename from packages/app/src/System/ProfileCache.ts rename to packages/system/src/ProfileCache.ts index fe49f371..7a21c6c9 100644 --- a/packages/app/src/System/ProfileCache.ts +++ b/packages/system/src/ProfileCache.ts @@ -1,13 +1,12 @@ -import { EventKind, HexKey, SystemInterface, TaggedRawEvent } from "System"; -import { ProfileCacheExpire } from "Const"; -import { mapEventToProfile, MetadataCache } from "Cache"; -import { UserCache } from "Cache/UserCache"; -import { PubkeyReplaceableNoteStore, RequestBuilder } from "System"; -import { unixNowMs } from "SnortUtils"; +import { EventKind, HexKey, SystemInterface, TaggedRawEvent, PubkeyReplaceableNoteStore, RequestBuilder } from "."; +import { ProfileCacheExpire } from "./Const"; +import { CacheStore, mapEventToProfile, MetadataCache } from "./cache"; +import { unixNowMs } from "./Util"; import debug from "debug"; export class ProfileLoaderService { #system: SystemInterface; + #cache: CacheStore; /** * List of pubkeys to fetch metadata for @@ -16,8 +15,9 @@ export class ProfileLoaderService { readonly #log = debug("ProfileCache"); - constructor(system: SystemInterface) { + constructor(system: SystemInterface, cache: CacheStore) { this.#system = system; + this.#cache = cache; this.#FetchMetadata(); } @@ -31,7 +31,7 @@ export class ProfileLoaderService { bufferNow.push(p); } } - UserCache.buffer(bufferNow); + this.#cache.buffer(bufferNow); } /** @@ -48,17 +48,17 @@ export class ProfileLoaderService { async onProfileEvent(e: Readonly) { const profile = mapEventToProfile(e); if (profile) { - await UserCache.update(profile); + await this.#cache.update(profile); } } async #FetchMetadata() { - const missingFromCache = await UserCache.buffer([...this.WantsMetadata]); + const missingFromCache = await this.#cache.buffer([...this.WantsMetadata]); const expire = unixNowMs() - ProfileCacheExpire; const expired = [...this.WantsMetadata] .filter(a => !missingFromCache.includes(a)) - .filter(a => (UserCache.getFromCache(a)?.loaded ?? 0) < expire); + .filter(a => (this.#cache.getFromCache(a)?.loaded ?? 0) < expire); const missing = new Set([...missingFromCache, ...expired]); if (missing.size > 0) { this.#log("Wants profiles: %d missing, %d expired", missingFromCache.length, expired.length); @@ -104,7 +104,7 @@ export class ProfileLoaderService { if (couldNotFetch.length > 0) { this.#log("No profiles: %o", couldNotFetch); const empty = couldNotFetch.map(a => - UserCache.update({ + this.#cache.update({ pubkey: a, loaded: unixNowMs() - ProfileCacheExpire + 5_000, // expire in 5s created: 69, diff --git a/packages/app/src/System/Query.ts b/packages/system/src/Query.ts similarity index 96% rename from packages/app/src/System/Query.ts rename to packages/system/src/Query.ts index 581d37f1..4ec3a4df 100644 --- a/packages/app/src/System/Query.ts +++ b/packages/system/src/Query.ts @@ -1,10 +1,9 @@ import { v4 as uuid } from "uuid"; import debug from "debug"; -import { Connection, ReqFilter, Nips, TaggedRawEvent } from "System"; -import { unixNowMs, unwrap } from "SnortUtils"; +import { Connection, ReqFilter, Nips, TaggedRawEvent } from "."; +import { unixNowMs, unwrap } from "./Util"; import { NoteStore } from "./NoteCollection"; -import { flatMerge, mergeSimilar, simpleMerge } from "./RequestMerger"; -import { eventMatchesFilter } from "./RequestMatcher"; +import { flatMerge } from "./RequestMerger"; import { BuiltRawReqFilter } from "./RequestBuilder"; import { expandFilter } from "./RequestExpander"; diff --git a/packages/app/src/System/RelayInfo.ts b/packages/system/src/RelayInfo.ts similarity index 100% rename from packages/app/src/System/RelayInfo.ts rename to packages/system/src/RelayInfo.ts diff --git a/packages/app/src/System/RequestBuilder.ts b/packages/system/src/RequestBuilder.ts similarity index 98% rename from packages/app/src/System/RequestBuilder.ts rename to packages/system/src/RequestBuilder.ts index dfbbb8b5..a565da9a 100644 --- a/packages/app/src/System/RequestBuilder.ts +++ b/packages/system/src/RequestBuilder.ts @@ -1,5 +1,5 @@ -import { ReqFilter, u256, HexKey, EventKind } from "System"; -import { appendDedupe, dedupe } from "SnortUtils"; +import { ReqFilter, u256, HexKey, EventKind } from "."; +import { appendDedupe, dedupe } from "./Util"; import { diffFilters } from "./RequestSplitter"; import { RelayCache, splitAllByWriteRelays, splitByWriteRelays } from "./GossipModel"; import { mergeSimilar } from "./RequestMerger"; diff --git a/packages/app/src/System/RequestExpander.ts b/packages/system/src/RequestExpander.ts similarity index 100% rename from packages/app/src/System/RequestExpander.ts rename to packages/system/src/RequestExpander.ts diff --git a/packages/app/src/System/RequestMatcher.ts b/packages/system/src/RequestMatcher.ts similarity index 100% rename from packages/app/src/System/RequestMatcher.ts rename to packages/system/src/RequestMatcher.ts diff --git a/packages/app/src/System/RequestMerger.ts b/packages/system/src/RequestMerger.ts similarity index 99% rename from packages/app/src/System/RequestMerger.ts rename to packages/system/src/RequestMerger.ts index bd588c25..db0403fe 100644 --- a/packages/app/src/System/RequestMerger.ts +++ b/packages/system/src/RequestMerger.ts @@ -1,4 +1,4 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "."; import { FlatReqFilter } from "./RequestExpander"; import { distance } from "./Util"; diff --git a/packages/app/src/System/RequestSplitter.ts b/packages/system/src/RequestSplitter.ts similarity index 94% rename from packages/app/src/System/RequestSplitter.ts rename to packages/system/src/RequestSplitter.ts index e1a3d653..2231d8b5 100644 --- a/packages/app/src/System/RequestSplitter.ts +++ b/packages/system/src/RequestSplitter.ts @@ -1,4 +1,4 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "."; import { deepEqual } from "./Util"; import { expandFilter } from "./RequestExpander"; import { flatMerge } from "./RequestMerger"; diff --git a/packages/app/src/System/SystemWorker.ts b/packages/system/src/SystemWorker.ts similarity index 80% rename from packages/app/src/System/SystemWorker.ts rename to packages/system/src/SystemWorker.ts index fb80e02a..ab9dfaf3 100644 --- a/packages/app/src/System/SystemWorker.ts +++ b/packages/system/src/SystemWorker.ts @@ -1,15 +1,10 @@ -import ExternalStore from "ExternalStore"; -import { - NoteStore, - Query, - NostrEvent, - RelaySettings, - RequestBuilder, - SystemSnapshot, - SystemInterface, - ConnectionStateSnapshot, - AuthHandler, -} from "System"; +import { SystemSnapshot, SystemInterface } from "."; +import { AuthHandler, ConnectionStateSnapshot, RelaySettings } from "./Connection"; +import ExternalStore from "./ExternalStore"; +import { NostrEvent } from "./Nostr"; +import { NoteStore } from "./NoteCollection"; +import { Query } from "./Query"; +import { RequestBuilder } from "./RequestBuilder"; export class SystemWorker extends ExternalStore implements SystemInterface { #port: MessagePort; diff --git a/packages/app/src/System/Tag.ts b/packages/system/src/Tag.ts similarity index 100% rename from packages/app/src/System/Tag.ts rename to packages/system/src/Tag.ts diff --git a/packages/app/src/System/Util.ts b/packages/system/src/Util.ts similarity index 68% rename from packages/app/src/System/Util.ts rename to packages/system/src/Util.ts index c5698739..a0053736 100644 --- a/packages/app/src/System/Util.ts +++ b/packages/system/src/Util.ts @@ -1,5 +1,8 @@ import * as utils from "@noble/curves/abstract/utils"; +import * as secp from "@noble/curves/secp256k1"; +import { sha256 as sha2 } from "@noble/hashes/sha256"; import { bech32 } from "bech32"; +import { NostrEvent, u256 } from "./Nostr"; export function unwrap(v: T | undefined | null): T { if (v === undefined || v === null) { @@ -84,3 +87,36 @@ export function distance(a: any, b: any): number { return distance; } + +export function dedupe(v: Array) { + return [...new Set(v)]; +} + +export function appendDedupe(a?: Array, b?: Array) { + return dedupe([...(a ?? []), ...(b ?? [])]); +} + +export function findTag(e: NostrEvent, tag: string) { + const maybeTag = e.tags.find(evTag => { + return evTag[0] === tag; + }); + return maybeTag && maybeTag[1]; +} + +export const sha256 = (str: string | Uint8Array): u256 => { + return utils.bytesToHex(sha2(str)); +} + +export function getPublicKey(privKey: string) { + return utils.bytesToHex(secp.schnorr.getPublicKey(privKey)); +} + +export function bech32ToHex(str: string) { + try { + const nKey = bech32.decode(str, 1_000); + const buff = bech32.fromWords(nKey.words); + return utils.bytesToHex(Uint8Array.from(buff)); + } catch (e) { + return str; + } +} diff --git a/packages/system/src/WorkQueue.ts b/packages/system/src/WorkQueue.ts new file mode 100644 index 00000000..37df22e0 --- /dev/null +++ b/packages/system/src/WorkQueue.ts @@ -0,0 +1,30 @@ +export interface WorkQueueItem { + next: () => Promise; + resolve(v: unknown): void; + reject(e: unknown): void; +} + +export async function processWorkQueue(queue?: Array, queueDelay = 200) { + while (queue && queue.length > 0) { + const v = queue.shift(); + if (v) { + try { + const ret = await v.next(); + v.resolve(ret); + } catch (e) { + v.reject(e); + } + } + } + setTimeout(() => processWorkQueue(queue, queueDelay), queueDelay); +} + +export const barrierQueue = async (queue: Array, then: () => Promise): Promise => { + return new Promise((resolve, reject) => { + queue.push({ + next: then, + resolve, + reject, + }); + }); +}; diff --git a/packages/system/src/cache/index.ts b/packages/system/src/cache/index.ts new file mode 100644 index 00000000..431318a0 --- /dev/null +++ b/packages/system/src/cache/index.ts @@ -0,0 +1,68 @@ +import { HexKey, NostrEvent, UserMetadata } from ".."; +import { hexToBech32, unixNowMs } from "../Util"; + +export interface MetadataCache extends UserMetadata { + /** + * When the object was saved in cache + */ + loaded: number; + + /** + * When the source metadata event was created + */ + created: number; + + /** + * The pubkey of the owner of this metadata + */ + pubkey: HexKey; + + /** + * The bech32 encoded pubkey + */ + npub: string; + + /** + * Pubkey of zapper service + */ + zapService?: HexKey; + + /** + * If the nip05 is valid for this user + */ + isNostrAddressValid: boolean; +} + +export function mapEventToProfile(ev: NostrEvent) { + try { + const data: UserMetadata = JSON.parse(ev.content); + return { + ...data, + pubkey: ev.pubkey, + npub: hexToBech32("npub", ev.pubkey), + created: ev.created_at, + loaded: unixNowMs(), + } as MetadataCache; + } catch (e) { + console.error("Failed to parse JSON", ev, e); + } +} + +export interface CacheStore { + preload(): Promise; + getFromCache(key?: string): T | undefined; + get(key?: string): Promise; + bulkGet(keys: Array): Promise>; + set(obj: T): Promise; + bulkSet(obj: Array): Promise; + update(m: TCachedWithCreated): Promise<"new" | "updated" | "refresh" | "no_change"> + + /** + * Loads a list of rows from disk cache + * @param keys List of ids to load + * @returns Keys that do not exist on disk cache + */ + buffer(keys: Array): Promise>; + + clear(): Promise; +} diff --git a/packages/app/src/System/index.ts b/packages/system/src/index.ts similarity index 58% rename from packages/app/src/System/index.ts rename to packages/system/src/index.ts index fd40e81e..4f11456c 100644 --- a/packages/app/src/System/index.ts +++ b/packages/system/src/index.ts @@ -1,13 +1,6 @@ -import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./Connection"; +import { AuthHandler, RelaySettings, ConnectionStateSnapshot } from "./Connection"; import { RequestBuilder } from "./RequestBuilder"; -import { EventBuilder } from "./EventBuilder"; -import { - FlatNoteStore, - NoteStore, - PubkeyReplaceableNoteStore, - ParameterizedReplaceableNoteStore, - ReplaceableNoteStore, -} from "./NoteCollection"; +import { NoteStore } from "./NoteCollection"; import { Query } from "./Query"; import { NostrEvent, ReqFilter } from "./Nostr"; @@ -18,6 +11,15 @@ export * from "./Links"; export { default as Tag } from "./Tag"; export * from "./Nips"; export * from "./RelayInfo"; +export * from "./EventExt"; +export * from "./Connection"; +export * from "./NoteCollection"; +export * from "./RequestBuilder"; +export * from "./EventPublisher"; +export * from "./EventBuilder"; +export * from "./NostrLink"; +export * from "./cache"; +export * from "./ProfileCache"; export interface SystemInterface { /** @@ -26,7 +28,7 @@ export interface SystemInterface { HandleAuth?: AuthHandler; get Sockets(): Array; GetQuery(id: string): Query | undefined; - Query(type: { new (): T }, req: RequestBuilder | null): Query | undefined; + Query(type: { new(): T }, req: RequestBuilder | null): Query | undefined; ConnectToRelay(address: string, options: RelaySettings): Promise; DisconnectRelay(address: string): void; BroadcastEvent(ev: NostrEvent): void; @@ -39,19 +41,4 @@ export interface SystemSnapshot { filters: Array; subFilters: Array; }>; -} - -export { - NoteStore, - RequestBuilder, - FlatNoteStore, - PubkeyReplaceableNoteStore, - ParameterizedReplaceableNoteStore, - ReplaceableNoteStore, - Query, - EventBuilder, - AuthHandler, - Connection, - RelaySettings, - ConnectionStateSnapshot, -}; +} \ No newline at end of file diff --git a/packages/app/src/System/NoteCollection.test.ts b/packages/system/tests/NoteCollection.test.ts similarity index 93% rename from packages/app/src/System/NoteCollection.test.ts rename to packages/system/tests/NoteCollection.test.ts index 00eb6086..613bc63d 100644 --- a/packages/app/src/System/NoteCollection.test.ts +++ b/packages/system/tests/NoteCollection.test.ts @@ -1,6 +1,6 @@ -import { TaggedRawEvent } from "System"; +import { TaggedRawEvent } from "../src/Nostr"; import { describe, expect } from "@jest/globals"; -import { FlatNoteStore, ReplaceableNoteStore } from "./NoteCollection"; +import { FlatNoteStore, ReplaceableNoteStore } from "../src/NoteCollection"; describe("NoteStore", () => { describe("flat", () => { diff --git a/packages/app/src/System/Query.test.ts b/packages/system/tests/Query.test.ts similarity index 92% rename from packages/app/src/System/Query.test.ts rename to packages/system/tests/Query.test.ts index ad80a1a4..3c026319 100644 --- a/packages/app/src/System/Query.test.ts +++ b/packages/system/tests/Query.test.ts @@ -1,9 +1,9 @@ -import { Connection } from "System"; +import { Connection } from "../src"; import { describe, expect } from "@jest/globals"; -import { Query, QueryBase } from "./Query"; +import { Query } from "../src/Query"; import { getRandomValues } from "crypto"; -import { FlatNoteStore } from "./NoteCollection"; -import { RequestStrategy } from "./RequestBuilder"; +import { FlatNoteStore } from "../src/NoteCollection"; +import { RequestStrategy } from "../src/RequestBuilder"; window.crypto = {} as any; window.crypto.getRandomValues = getRandomValues as any; diff --git a/packages/app/src/System/RequestBuilder.test.ts b/packages/system/tests/RequestBuilder.test.ts similarity index 97% rename from packages/app/src/System/RequestBuilder.test.ts rename to packages/system/tests/RequestBuilder.test.ts index e2546cda..b0ec6f99 100644 --- a/packages/app/src/System/RequestBuilder.test.ts +++ b/packages/system/tests/RequestBuilder.test.ts @@ -1,5 +1,5 @@ -import { RelayCache } from "./GossipModel"; -import { RequestBuilder, RequestStrategy } from "./RequestBuilder"; +import { RelayCache } from "../src/GossipModel"; +import { RequestBuilder, RequestStrategy } from "../src/RequestBuilder"; import { describe, expect } from "@jest/globals"; const DummyCache = { diff --git a/packages/app/src/System/RequestExpander.test.ts b/packages/system/tests/RequestExpander.test.ts similarity index 96% rename from packages/app/src/System/RequestExpander.test.ts rename to packages/system/tests/RequestExpander.test.ts index 0ccb58d1..d87faf7b 100644 --- a/packages/app/src/System/RequestExpander.test.ts +++ b/packages/system/tests/RequestExpander.test.ts @@ -1,4 +1,4 @@ -import { expandFilter } from "./RequestExpander"; +import { expandFilter } from "../src/RequestExpander"; describe("RequestExpander", () => { test("expand filter", () => { diff --git a/packages/app/src/System/RequestMatcher.test.ts b/packages/system/tests/RequestMatcher.test.ts similarity index 88% rename from packages/app/src/System/RequestMatcher.test.ts rename to packages/system/tests/RequestMatcher.test.ts index 49754ff5..0b7a4b39 100644 --- a/packages/app/src/System/RequestMatcher.test.ts +++ b/packages/system/tests/RequestMatcher.test.ts @@ -1,4 +1,4 @@ -import { eventMatchesFilter } from "./RequestMatcher"; +import { eventMatchesFilter } from "../src/RequestMatcher"; describe("RequestMatcher", () => { it("should match simple filter", () => { diff --git a/packages/app/src/System/RequestMerger.test.ts b/packages/system/tests/RequestMerger.test.ts similarity index 93% rename from packages/app/src/System/RequestMerger.test.ts rename to packages/system/tests/RequestMerger.test.ts index b2020d36..d9ac51cf 100644 --- a/packages/app/src/System/RequestMerger.test.ts +++ b/packages/system/tests/RequestMerger.test.ts @@ -1,7 +1,7 @@ -import { ReqFilter } from "System"; -import { filterIncludes, flatMerge, mergeSimilar, simpleMerge } from "./RequestMerger"; -import { FlatReqFilter, expandFilter } from "./RequestExpander"; -import { distance } from "./Util"; +import { ReqFilter } from "../src"; +import { filterIncludes, flatMerge, mergeSimilar, simpleMerge } from "../src/RequestMerger"; +import { FlatReqFilter, expandFilter } from "../src/RequestExpander"; +import { distance } from "../src/Util"; describe("RequestMerger", () => { it("should simple merge authors", () => { diff --git a/packages/app/src/System/RequestSplitter.test.ts b/packages/system/tests/RequestSplitter.test.ts similarity index 96% rename from packages/app/src/System/RequestSplitter.test.ts rename to packages/system/tests/RequestSplitter.test.ts index e6caa5a7..7e639e34 100644 --- a/packages/app/src/System/RequestSplitter.test.ts +++ b/packages/system/tests/RequestSplitter.test.ts @@ -1,6 +1,6 @@ -import { ReqFilter } from "System"; +import { ReqFilter } from "../src"; import { describe, expect } from "@jest/globals"; -import { diffFilters } from "./RequestSplitter"; +import { diffFilters } from "../src/RequestSplitter"; describe("RequestSplitter", () => { test("single filter add value", () => { diff --git a/packages/system/tests/Util.test.ts b/packages/system/tests/Util.test.ts new file mode 100644 index 00000000..baebd7a2 --- /dev/null +++ b/packages/system/tests/Util.test.ts @@ -0,0 +1,117 @@ +import { distance } from "../src/Util"; + +describe("distance", () => { + it("should have 0 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "a", + }; + expect(distance(a, b)).toEqual(0); + }); + it("should have 1 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "b", + }; + expect(distance(a, b)).toEqual(1); + }); + it("should have 10 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "a", + kinds: 1, + }; + expect(distance(a, b)).toEqual(10); + }); + it("should have 11 distance", () => { + const a = { + ids: "a", + }; + const b = { + ids: "b", + kinds: 1, + }; + expect(distance(a, b)).toEqual(11); + }); + it("should have 1 distance, arrays", () => { + const a = { + since: 1, + until: 100, + kinds: [1], + authors: ["kieran", "snort", "c", "d", "e"], + }; + const b = { + since: 1, + until: 100, + kinds: [6969], + authors: ["kieran", "snort", "c", "d", "e"], + }; + expect(distance(a, b)).toEqual(1); + }); + it("should have 1 distance, array change extra", () => { + const a = { + since: 1, + until: 100, + kinds: [1], + authors: ["f", "kieran", "snort", "c", "d"], + }; + const b = { + since: 1, + until: 100, + kinds: [1], + authors: ["kieran", "snort", "c", "d", "e"], + }; + expect(distance(a, b)).toEqual(1); + }); +}); + + +describe("tryParseNostrLink", () => { + it("is a valid nostr link", () => { + expect(parseNostrLink("nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ + id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", + type: NostrPrefix.PublicKey, + }); + expect(parseNostrLink("web+nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg")).toMatchObject({ + id: "7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e", + type: NostrPrefix.PublicKey, + }); + expect(parseNostrLink("nostr:note15449edq4qa5wzgqvh8td0q0dp6hwtes4pknsrm7eygeenhlj99xsq94wu9")).toMatchObject({ + id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", + type: NostrPrefix.Note, + }); + expect( + parseNostrLink( + "nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p" + ) + ).toMatchObject({ + id: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", + type: NostrPrefix.Profile, + relays: ["wss://r.x.com", "wss://djbas.sadkb.com"], + }); + expect(parseNostrLink("nostr:nevent1qqs226juks2sw68pyqxtn4khs8ksath9uc2smfcpalvjyvuemlezjngrd87dq")).toMatchObject({ + id: "a56a5cb4150768e1200cb9d6d781ed0eaee5e6150da701efd9223399dff2294d", + type: NostrPrefix.Event, + }); + expect( + parseNostrLink( + "nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu" + ) + ).toMatchObject({ + id: "ipsum", + type: NostrPrefix.Address, + relays: ["wss://relay.nostr.org"], + author: "a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919", + kind: 30023, + }); + }); + test.each(["nostr:npub", "web+nostr:npub", "nostr:nevent1xxx"])("should return false for invalid nostr links", lb => { + expect(tryParseNostrLink(lb)).toBeUndefined(); + }); +}); diff --git a/packages/system/tests/setupTests.ts b/packages/system/tests/setupTests.ts new file mode 100644 index 00000000..4930f245 --- /dev/null +++ b/packages/system/tests/setupTests.ts @@ -0,0 +1,3 @@ +import { TextEncoder, TextDecoder } from "util"; + +Object.assign(global, { TextDecoder, TextEncoder }); diff --git a/packages/system/tsconfig.json b/packages/system/tsconfig.json new file mode 100644 index 00000000..dca184be --- /dev/null +++ b/packages/system/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "baseUrl": "src", + "target": "ES2020", + "moduleResolution": "node", + "esModuleInterop": true, + "noImplicitOverride": true, + "module": "CommonJS", + "strict": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "skipLibCheck": true + }, + "include": ["src"], + "files": ["src/index.ts"] +} diff --git a/packages/app/src/System/worker.ts b/packages/system/worker.ts similarity index 88% rename from packages/app/src/System/worker.ts rename to packages/system/worker.ts index 4f47dad8..88315188 100644 --- a/packages/app/src/System/worker.ts +++ b/packages/system/worker.ts @@ -1,5 +1,5 @@ /// -import { UsersRelaysCache } from "Cache/UserRelayCache"; +import { UsersRelaysCache } from "../Cache/UserRelayCache"; import { NostrSystem } from "."; declare const self: SharedWorkerGlobalScope;