diff --git a/package-lock.json b/package-lock.json index 4a298e2..65e7a2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "i18next-browser-languagedetector": "^7.2.0", "idb-keyval": "^6.2.1", "lodash": "^4.17.21", - "nostr-tools": "^1.16.0", + "nostr-tools": "^2.0.3", "solid-js": "^1.8.7", "tailwindcss": "^3.4.0", "zod": "^3.22.4" @@ -5494,16 +5494,17 @@ } }, "node_modules/nostr-tools": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-1.16.0.tgz", - "integrity": "sha512-sx/aOl0gmkeHVoIVbyOhEQhzF88NsrBXMC8bsjhPASqA6oZ8uSOAyEGgRLMfC3SKgzQD5Gr6KvDoAahaD6xKcg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.0.3.tgz", + "integrity": "sha512-A7/sBaeBA7Vmi3q1Or62FYbU4OuNBOfQmSxn4/sEK5Z6L4Ql9dwSq8H/mrxsiCQHfbLaVHBOmxLOOd3070/xCA==", "dependencies": { - "@noble/ciphers": "^0.2.0", - "@noble/curves": "1.1.0", + "@noble/ciphers": "0.2.0", + "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" + "@scure/bip39": "1.2.1", + "nostr-wasm": "v0.0.3" }, "peerDependencies": { "typescript": ">=5.0.0" @@ -5514,6 +5515,33 @@ } } }, + "node_modules/nostr-tools/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-wasm": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.0.3.tgz", + "integrity": "sha512-zz5INXiuya10s+zsNmW2k4xH47j+Ikgxn5SL8xt/quGBNWn/A6+blVqT3J6yjkZim/gyVC/9GXd0jH4w3w1HZA==" + }, "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", @@ -12599,18 +12627,41 @@ "dev": true }, "nostr-tools": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-1.16.0.tgz", - "integrity": "sha512-sx/aOl0gmkeHVoIVbyOhEQhzF88NsrBXMC8bsjhPASqA6oZ8uSOAyEGgRLMfC3SKgzQD5Gr6KvDoAahaD6xKcg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.0.3.tgz", + "integrity": "sha512-A7/sBaeBA7Vmi3q1Or62FYbU4OuNBOfQmSxn4/sEK5Z6L4Ql9dwSq8H/mrxsiCQHfbLaVHBOmxLOOd3070/xCA==", "requires": { - "@noble/ciphers": "^0.2.0", - "@noble/curves": "1.1.0", + "@noble/ciphers": "0.2.0", + "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" + "@scure/bip39": "1.2.1", + "nostr-wasm": "v0.0.3" + }, + "dependencies": { + "@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "requires": { + "@noble/hashes": "1.3.2" + }, + "dependencies": { + "@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==" + } + } + } } }, + "nostr-wasm": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.0.3.tgz", + "integrity": "sha512-zz5INXiuya10s+zsNmW2k4xH47j+Ikgxn5SL8xt/quGBNWn/A6+blVqT3J6yjkZim/gyVC/9GXd0jH4w3w1HZA==" + }, "npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", diff --git a/package.json b/package.json index 911ba25..3fcd443 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "i18next-browser-languagedetector": "^7.2.0", "idb-keyval": "^6.2.1", "lodash": "^4.17.21", - "nostr-tools": "^1.16.0", + "nostr-tools": "^2.0.3", "solid-js": "^1.8.7", "tailwindcss": "^3.4.0", "zod": "^3.22.4" diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index ae94a73..d51c65c 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -16,7 +16,8 @@ import EllipsisHorizontal from 'heroicons/24/outline/ellipsis-horizontal.svg'; import HeartOutlined from 'heroicons/24/outline/heart.svg'; import Plus from 'heroicons/24/outline/plus.svg'; import HeartSolid from 'heroicons/24/solid/heart.svg'; -import { type Event as NostrEvent, nip19 } from 'nostr-tools'; +import { noteEncode } from 'nostr-tools/nip19'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import ContextMenu, { MenuItem } from '@/components/ContextMenu'; import EmojiDisplay from '@/components/EmojiDisplay'; @@ -41,8 +42,6 @@ export type ActionProps = { onClickReply: () => void; }; -const { noteEncode } = nip19; - const emojiDataToReactionTypes = (emoji: EmojiData): ReactionTypes => { if (emoji.native != null) { return { type: 'Emoji', content: emoji.native }; diff --git a/src/components/EventLink.tsx b/src/components/EventLink.tsx index 3cacd77..34eeb80 100644 --- a/src/components/EventLink.tsx +++ b/src/components/EventLink.tsx @@ -1,12 +1,10 @@ import { Show, type Component } from 'solid-js'; -import { Kind, nip19 } from 'nostr-tools'; - -const { noteEncode, neventEncode } = nip19; +import { noteEncode, neventEncode } from 'nostr-tools/nip19'; type EventLinkProps = { eventId: string; - kind?: Kind; + kind?: number; }; const tryEncodeNote = (eventId: string) => { @@ -29,10 +27,7 @@ const tryEncodeNevent = (eventId: string) => { const EventLink: Component = (props) => ( diff --git a/src/components/NotePostForm.tsx b/src/components/NotePostForm.tsx index 992b6ad..4e698b7 100644 --- a/src/components/NotePostForm.tsx +++ b/src/components/NotePostForm.tsx @@ -6,7 +6,7 @@ import Photo from 'heroicons/24/outline/photo.svg'; import XMark from 'heroicons/24/outline/x-mark.svg'; import PaperAirplane from 'heroicons/24/solid/paper-airplane.svg'; import uniq from 'lodash/uniq'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import EmojiPicker, { EmojiData } from '@/components/EmojiPicker'; import UserNameDisplay from '@/components/UserDisplayName'; diff --git a/src/components/column/ChannelColumn.tsx b/src/components/column/ChannelColumn.tsx index 846adbc..ebf0159 100644 --- a/src/components/column/ChannelColumn.tsx +++ b/src/components/column/ChannelColumn.tsx @@ -1,7 +1,7 @@ import { Component } from 'solid-js'; import ChatBubbleLeftRight from 'heroicons/24/outline/chat-bubble-left-right.svg'; -import { Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; import BasicColumnHeader from '@/components/column/BasicColumnHeader'; import Column from '@/components/column/Column'; diff --git a/src/components/event/ChannelMetaDisplay.tsx b/src/components/event/ChannelMetaDisplay.tsx index f9738de..4089145 100644 --- a/src/components/event/ChannelMetaDisplay.tsx +++ b/src/components/event/ChannelMetaDisplay.tsx @@ -1,7 +1,7 @@ import { Component, Show } from 'solid-js'; import ChatBubbleLeftRight from 'heroicons/24/outline/chat-bubble-left-right.svg'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { parseChannelMeta } from '@/nostr/event/channel'; diff --git a/src/components/event/EventDisplay.tsx b/src/components/event/EventDisplay.tsx index 5d54e05..a9191f0 100644 --- a/src/components/event/EventDisplay.tsx +++ b/src/components/event/EventDisplay.tsx @@ -1,6 +1,7 @@ import { Switch, Match, Component } from 'solid-js'; -import { Kind, type Event as NostrEvent } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; // import ChannelInfo from '@/components/event/ChannelInfo'; // eslint-disable-next-line import/no-cycle @@ -13,7 +14,7 @@ export type EventDisplayProps = { event: NostrEvent; embedding?: boolean; actions?: boolean; - ensureKinds?: Kind[]; + ensureKinds?: number[]; }; const EventDisplay: Component = (props) => { @@ -39,10 +40,10 @@ const EventDisplay: Component = (props) => { - + - + diff --git a/src/components/event/Reaction.tsx b/src/components/event/Reaction.tsx index 4fa6457..6c21540 100644 --- a/src/components/event/Reaction.tsx +++ b/src/components/event/Reaction.tsx @@ -1,6 +1,6 @@ import { type Component, Show } from 'solid-js'; -import { type Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import EmojiDisplay from '@/components/EmojiDisplay'; import TextNote from '@/components/event/TextNote'; diff --git a/src/components/event/Repost.tsx b/src/components/event/Repost.tsx index c4727db..bc67455 100644 --- a/src/components/event/Repost.tsx +++ b/src/components/event/Repost.tsx @@ -2,7 +2,7 @@ import { type Component, createMemo } from 'solid-js'; import ArrowPathRoundedSquare from 'heroicons/24/outline/arrow-path-rounded-square.svg'; -import { Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; // eslint-disable-next-line import/no-cycle import EventDisplayById from '@/components/event/EventDisplayById'; diff --git a/src/components/event/TextNote.tsx b/src/components/event/TextNote.tsx index ea34254..32372bc 100644 --- a/src/components/event/TextNote.tsx +++ b/src/components/event/TextNote.tsx @@ -1,6 +1,6 @@ import { Show, For, createSignal, createMemo, type Component } from 'solid-js'; -import { type Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import Actions from '@/components/Actions'; // eslint-disable-next-line import/no-cycle diff --git a/src/components/event/textNote/MentionedEventDisplay.tsx b/src/components/event/textNote/MentionedEventDisplay.tsx index 10840cf..06c464a 100644 --- a/src/components/event/textNote/MentionedEventDisplay.tsx +++ b/src/components/event/textNote/MentionedEventDisplay.tsx @@ -1,6 +1,6 @@ import { Show } from 'solid-js'; -import { Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; // eslint-disable-next-line import/no-cycle import EventDisplayById from '@/components/event/EventDisplayById'; @@ -24,7 +24,7 @@ const MentionedEventDisplay = (props: MentionedEventDisplayProps) => ( eventId={props.mentionedEvent.eventId} embedding={false} actions={false} - ensureKinds={[Kind.Text]} + ensureKinds={[Kind.ShortTextNote]} /> )} diff --git a/src/components/event/textNote/TextNoteContentDisplay.tsx b/src/components/event/textNote/TextNoteContentDisplay.tsx index 3924333..fbbddf4 100644 --- a/src/components/event/textNote/TextNoteContentDisplay.tsx +++ b/src/components/event/textNote/TextNoteContentDisplay.tsx @@ -1,6 +1,6 @@ import { For } from 'solid-js'; -import { Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; // eslint-disable-next-line import/no-cycle import EventDisplayById from '@/components/event/EventDisplayById'; @@ -88,7 +88,7 @@ const TextNoteContentDisplay = (props: TextNoteContentDisplayProps) => { eventId={item.data.data} actions={false} embedding={false} - ensureKinds={[Kind.Text]} + ensureKinds={[Kind.ShortTextNote]} /> ); diff --git a/src/components/modal/EventDebugModal.tsx b/src/components/modal/EventDebugModal.tsx index 8819e10..fc4e441 100644 --- a/src/components/modal/EventDebugModal.tsx +++ b/src/components/modal/EventDebugModal.tsx @@ -1,6 +1,6 @@ import { Component, createMemo } from 'solid-js'; -import { type Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import BasicModal from '@/components/modal/BasicModal'; import Copy from '@/components/utils/Copy'; diff --git a/src/components/timeline/Bookmark.tsx b/src/components/timeline/Bookmark.tsx index ed2f365..8801ef4 100644 --- a/src/components/timeline/Bookmark.tsx +++ b/src/components/timeline/Bookmark.tsx @@ -1,6 +1,7 @@ import { For, type Component, createMemo } from 'solid-js'; -import { Kind, type Event as NostrEvent } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import ColumnItem from '@/components/ColumnItem'; import EventDisplayById from '@/components/event/EventDisplayById'; @@ -40,7 +41,7 @@ const Bookmark: Component = (props) => { {(eventId) => ( - + )} diff --git a/src/components/timeline/Notification.tsx b/src/components/timeline/Notification.tsx index 41bd381..af888ab 100644 --- a/src/components/timeline/Notification.tsx +++ b/src/components/timeline/Notification.tsx @@ -1,6 +1,7 @@ import { For, Switch, Match, type Component, Show } from 'solid-js'; -import { Kind, type Event as NostrEvent } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import ColumnItem from '@/components/ColumnItem'; import Reaction from '@/components/event/Reaction'; @@ -20,18 +21,18 @@ const Notification: Component = (props) => { {(event) => ( unknown event}> - + - + {/* TODO ちゃんとnotification用のコンポーネント使う */} - + diff --git a/src/components/timeline/Timeline.tsx b/src/components/timeline/Timeline.tsx index a8486ac..20a57d3 100644 --- a/src/components/timeline/Timeline.tsx +++ b/src/components/timeline/Timeline.tsx @@ -1,6 +1,6 @@ import { For, type Component, Show } from 'solid-js'; -import { type Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import ColumnItem from '@/components/ColumnItem'; import EventDisplay from '@/components/event/EventDisplay'; diff --git a/src/components/timeline/TimelineContentDisplay.tsx b/src/components/timeline/TimelineContentDisplay.tsx index 6690b46..9fd807f 100644 --- a/src/components/timeline/TimelineContentDisplay.tsx +++ b/src/components/timeline/TimelineContentDisplay.tsx @@ -1,7 +1,8 @@ import { Switch, Match, type Component } from 'solid-js'; import uniq from 'lodash/uniq'; -import { Filter, Event as NostrEvent } from 'nostr-tools'; +import { type Filter } from 'nostr-tools/filter'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import Timeline from '@/components/timeline/Timeline'; import { type TimelineContent } from '@/components/timeline/TimelineContext'; diff --git a/src/components/timeline/TimelineContext.tsx b/src/components/timeline/TimelineContext.tsx index 62d1a3d..419833a 100644 --- a/src/components/timeline/TimelineContext.tsx +++ b/src/components/timeline/TimelineContext.tsx @@ -1,6 +1,6 @@ import { createContext, useContext } from 'solid-js'; -import { Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import { createStore } from 'solid-js/store'; export type TimelineContent = { diff --git a/src/core/column.ts b/src/core/column.ts index ba77fa0..ec296d1 100644 --- a/src/core/column.ts +++ b/src/core/column.ts @@ -1,5 +1,5 @@ // import { z } from 'zod'; -import { type Filter } from 'nostr-tools'; +import { type Filter } from 'nostr-tools/filter'; import { type ColumnProps } from '@/components/column/Column'; import { ContentFilter } from '@/core/contentFilter'; diff --git a/src/core/useConfig.ts b/src/core/useConfig.ts index cbbe4b6..8273617 100644 --- a/src/core/useConfig.ts +++ b/src/core/useConfig.ts @@ -2,7 +2,8 @@ import { type Accessor, type Setter } from 'solid-js'; import { sortBy } from 'lodash'; import uniq from 'lodash/uniq'; -import { Kind, type Event as NostrEvent } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import { ColumnType, @@ -194,7 +195,7 @@ const useConfig = (): UseConfig => { const isPubkeyMuted = (pubkey: string) => config.mutedPubkeys.includes(pubkey); const hasMutedKeyword = (event: NostrEvent) => { - if (event.kind === (Kind.Text as number)) { + if (event.kind === Kind.ShortTextNote) { return config.mutedKeywords.some((keyword) => event.content.includes(keyword)); } return false; @@ -205,7 +206,7 @@ const useConfig = (): UseConfig => { return ( isPubkeyMuted(event.pubkey) || ev.taggedPubkeys().some(isPubkeyMuted) || - (event.kind === (Kind.Text as number) && hasMutedKeyword(event)) + (event.kind === Kind.ShortTextNote && hasMutedKeyword(event)) ); }; diff --git a/src/nostr/event.ts b/src/nostr/event.ts index 4ba64dd..9edaa4a 100644 --- a/src/nostr/event.ts +++ b/src/nostr/event.ts @@ -1,4 +1,4 @@ -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import GenericEvent from '@/nostr/event/GenericEvent'; import Reaction from '@/nostr/event/Reaction'; diff --git a/src/nostr/event/GenericEvent.ts b/src/nostr/event/GenericEvent.ts index 125e7a3..0700b93 100644 --- a/src/nostr/event/GenericEvent.ts +++ b/src/nostr/event/GenericEvent.ts @@ -1,4 +1,4 @@ -import { Kind, Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import TagsBase from '@/nostr/event/TagsBase'; @@ -15,7 +15,7 @@ export default class GenericEvent extends TagsBase { return this.rawEvent.sig; } - get kind(): Kind { + get kind(): number { return this.rawEvent.kind; } diff --git a/src/nostr/event/Reaction.ts b/src/nostr/event/Reaction.ts index 5a6bda3..4351a3f 100644 --- a/src/nostr/event/Reaction.ts +++ b/src/nostr/event/Reaction.ts @@ -1,4 +1,5 @@ -import { Event as NostrEvent, Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import GenericEvent from '@/nostr/event/GenericEvent'; @@ -30,7 +31,7 @@ const reactionToReactionTypes = (event: Reaction): ReactionTypes => { export default class Reaction extends GenericEvent { constructor(rawEvent: NostrEvent) { - if (rawEvent.kind !== (Kind.Reaction as number)) { + if (rawEvent.kind !== Kind.Reaction) { throw new TypeError('kind should be 7'); } super(rawEvent); diff --git a/src/nostr/event/TextNote.test.ts b/src/nostr/event/TextNote.test.ts index eb5fc56..db98408 100644 --- a/src/nostr/event/TextNote.test.ts +++ b/src/nostr/event/TextNote.test.ts @@ -1,6 +1,6 @@ import assert from 'assert'; -import { Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; import { describe, it } from 'vitest'; import TextNote from '@/nostr/event/TextNote'; @@ -142,7 +142,7 @@ describe('TextNote', () => { it('should return true if content of the event includes a NIP-19-styled note ID', () => { const textnote = new TextNote({ id: '', - kind: Kind.Text, + kind: Kind.ShortTextNote, content: 'nostr:note1qpwq08jv0sgrz68qev6eyu9vj6n2gmjl7n8g73jruzp37mguy3gq8d7asa', created_at: 0, pubkey: '', @@ -159,7 +159,7 @@ describe('TextNote', () => { it('should return true if content of the event includes a NIP-19-styled nevent ID', () => { const textnote = new TextNote({ id: '', - kind: Kind.Text, + kind: Kind.ShortTextNote, content: 'nostr:nevent1qqsttdc4rmxn8fqmk9s6823fqvpcmlm8ry6dmtu4m2snv0cm9sv70kq6urpy5', created_at: 0, pubkey: '', @@ -178,7 +178,7 @@ describe('TextNote', () => { it('should return a reply MarkedEventTag if the event has a reply tag', () => { const textnote = new TextNote({ id: '', - kind: Kind.Text, + kind: Kind.ShortTextNote, content: '', created_at: 0, pubkey: '', diff --git a/src/nostr/event/TextNote.ts b/src/nostr/event/TextNote.ts index 31cbb6d..c5a49cb 100644 --- a/src/nostr/event/TextNote.ts +++ b/src/nostr/event/TextNote.ts @@ -1,11 +1,12 @@ -import { type Event as NostrEvent, Kind } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import TextNoteLike from '@/nostr/event/TextNoteLike'; export default class TextNote extends TextNoteLike { constructor(rawEvent: NostrEvent) { - if (rawEvent.kind !== (Kind.Text as number)) { - throw new TypeError('kind should be 1'); + if (rawEvent.kind !== Kind.ShortTextNote) { + throw new TypeError(`kind should be 1 but it was ${rawEvent.kind}`); } super(rawEvent); } diff --git a/src/nostr/event/comparator.test.ts b/src/nostr/event/comparator.test.ts index 2a52b7c..717b906 100644 --- a/src/nostr/event/comparator.test.ts +++ b/src/nostr/event/comparator.test.ts @@ -1,6 +1,6 @@ import assert from 'assert'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { describe, it } from 'vitest'; import { compareEvents, pickLatestEvent } from '@/nostr/event/comparator'; diff --git a/src/nostr/event/comparator.ts b/src/nostr/event/comparator.ts index e5371b2..32bb62b 100644 --- a/src/nostr/event/comparator.ts +++ b/src/nostr/event/comparator.ts @@ -1,4 +1,4 @@ -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; /** * compareEvents compares events by created_at and id. diff --git a/src/nostr/parseTextNote.ts b/src/nostr/parseTextNote.ts index d7cf725..bb165db 100644 --- a/src/nostr/parseTextNote.ts +++ b/src/nostr/parseTextNote.ts @@ -1,11 +1,8 @@ -import { nip19 } from 'nostr-tools'; -import { DecodeResult } from 'nostr-tools/lib/nip19'; +import { decode, type DecodeResult } from 'nostr-tools/nip19'; import isValidId from '@/nostr/event/isValidId'; import TagsBase from '@/nostr/event/TagsBase'; -const { decode } = nip19; - export type PlainText = { type: 'PlainText'; content: string; diff --git a/src/nostr/query.ts b/src/nostr/query.ts index 36486bf..f1a0e61 100644 --- a/src/nostr/query.ts +++ b/src/nostr/query.ts @@ -1,6 +1,6 @@ import { QueryClient, QueryKey } from '@tanstack/solid-query'; import { uniqBy } from 'lodash'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { compareEvents, pickLatestEvent, sortEvents } from '@/nostr/event/comparator'; import { BatchedEventsTask, registerTask } from '@/nostr/useBatchedEvents'; diff --git a/src/nostr/useBatchedEvents.ts b/src/nostr/useBatchedEvents.ts index fb28cbd..f1103f7 100644 --- a/src/nostr/useBatchedEvents.ts +++ b/src/nostr/useBatchedEvents.ts @@ -1,4 +1,7 @@ -import { type Event as NostrEvent, type Filter, Kind, utils } from 'nostr-tools'; +import { type Filter } from 'nostr-tools/filter'; +import * as Kind from 'nostr-tools/kinds'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; +import { insertEventIntoDescendingList } from 'nostr-tools/utils'; import useConfig from '@/core/useConfig'; import { genericEvent } from '@/nostr/event'; @@ -35,7 +38,7 @@ type TaskArg = TaskArgs[number]; export class BatchedEventsTask extends ObservableTask { addEvent(event: NostrEvent) { - this.updateWith((current) => utils.insertEventIntoDescendingList(current ?? [], event)); + this.updateWith((current) => insertEventIntoDescendingList(current ?? [], event)); } firstEventPromise(): Promise { @@ -64,9 +67,6 @@ setInterval(() => { setActiveBatchSubscriptions(count); }, 1000); -const isParameterizedReplaceableEvent = (event: NostrEvent) => - event.kind >= 30000 && event.kind < 40000; - const keyForParameterizedReplaceableEvent = ({ kind, author, @@ -220,22 +220,22 @@ export const tasksRequestBuilder = (tasks: BatchedEventsTask[]) => { ]; const resolve = (event: NostrEvent) => { - if (event.kind === (Kind.Metadata as number)) { + if (event.kind === Kind.Metadata) { if (profileTasks.resolve(event)) return; } - if (event.kind === (Kind.Contacts as number)) { + if (event.kind === Kind.Contacts) { if (followingsTasks.resolve(event)) return; } - if (event.kind === (Kind.Repost as number)) { + if (event.kind === Kind.Repost) { if (repostsTasks.resolve(event)) return; } - if (event.kind === (Kind.Reaction as number)) { + if (event.kind === Kind.Reaction) { if (reactionsTasks.resolve(event)) return; } - if (event.kind === (Kind.Zap as number)) { + if (event.kind === Kind.Zap) { if (zapReceiptsTasks.resolve(event)) return; } - if (isParameterizedReplaceableEvent(event)) { + if (Kind.isParameterizedReplaceableKind(event.kind)) { if (parameterizedReplaceableEventsTasks.resolve(event)) return; } eventTasks.resolve(event); @@ -279,18 +279,17 @@ const { addTask, removeTask } = useBatch(() => ({ const { config } = useConfig(); const pool = usePool(); - const sub = pool().sub(config().relayUrls, filters, {}); - count += 1; - - sub.on('event', (event: NostrEvent & { id: string }) => { - builder.resolve(event); - }); - - sub.on('eose', () => { - finalizeTasks(); - sub.unsub(); - count -= 1; + const sub = pool().subscribeMany(config().relayUrls, filters, { + eoseTimeout: 15000, + onevent: (event: NostrEvent) => { + builder.resolve(event); + }, + oneose: () => { + finalizeTasks(); + sub.close(); + count -= 1; + }, }); }, })); diff --git a/src/nostr/useBookMarks.ts b/src/nostr/useBookMarks.ts index ce6ee30..f28036e 100644 --- a/src/nostr/useBookMarks.ts +++ b/src/nostr/useBookMarks.ts @@ -1,7 +1,5 @@ import { createMemo } from 'solid-js'; -import { Kind } from 'nostr-tools'; - import useConfig from '@/core/useConfig'; import useSubscription from '@/nostr/useSubscription'; @@ -15,7 +13,7 @@ export default function useBookmarks(propsProvider: () => UseBookmarksProps) { const { events } = useSubscription(() => ({ relayUrls: config().relayUrls, - filters: [{ kinds: [30001 as Kind], authors: [props().pubkey] }], + filters: [{ kinds: [30001], authors: [props().pubkey] }], continuous: true, })); diff --git a/src/nostr/useCommands.ts b/src/nostr/useCommands.ts index b6bfc37..14e3980 100644 --- a/src/nostr/useCommands.ts +++ b/src/nostr/useCommands.ts @@ -1,6 +1,6 @@ -import { getEventHash, Kind, verifySignature, type UnsignedEvent } from 'nostr-tools'; +import * as Kind from 'nostr-tools/kinds'; +import { verifyEvent, getEventHash, type UnsignedEvent } from 'nostr-tools/pure'; -// import '@/types/nostr.d'; import { ProfileWithOtherProperties, Profile } from '@/nostr/event/Profile'; import { ReactionTypes } from '@/nostr/event/Reaction'; import usePool from '@/nostr/usePool'; @@ -87,7 +87,7 @@ const useCommands = () => { throw new Error('NIP-07 implementation not found'); } const signedEvent = await window.nostr.signEvent(preSignedEvent); - if (!verifySignature({ ...signedEvent, id })) { + if (!verifyEvent({ ...signedEvent, id })) { throw new Error('nostr.signEvent returned invalid data'); } @@ -109,7 +109,7 @@ const useCommands = () => { const tags = buildTags(params); const preSignedEvent: UnsignedEvent = { - kind: 1, + kind: Kind.ShortTextNote, pubkey, created_at: epoch(), tags, @@ -145,7 +145,7 @@ const useCommands = () => { } const preSignedEvent: UnsignedEvent = { - kind: 7, + kind: Kind.Reaction, pubkey, created_at: epoch(), tags, diff --git a/src/nostr/useEvent.ts b/src/nostr/useEvent.ts index ab13495..94e513d 100644 --- a/src/nostr/useEvent.ts +++ b/src/nostr/useEvent.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import { registerTask, BatchedEventsTask, EventTask } from '@/nostr/useBatchedEvents'; import timeout from '@/utils/timeout'; diff --git a/src/nostr/useFollowers.ts b/src/nostr/useFollowers.ts index 5c98eb0..c9f1eaa 100644 --- a/src/nostr/useFollowers.ts +++ b/src/nostr/useFollowers.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import uniq from 'lodash/uniq'; -import { Kind } from 'nostr-tools'; +import { Metadata } from 'nostr-tools/kinds'; import useConfig from '@/core/useConfig'; import useSubscription from '@/nostr/useSubscription'; @@ -16,7 +16,7 @@ export default function useFollowers(propsProvider: () => UseFollowersProps) { const { events } = useSubscription(() => ({ relayUrls: config().relayUrls, - filters: [{ kinds: [Kind.Contacts], '#p': [props().pubkey] }], + filters: [{ kinds: [Metadata], '#p': [props().pubkey] }], limit: Number.MAX_SAFE_INTEGER, continuous: true, })); diff --git a/src/nostr/useFollowings.ts b/src/nostr/useFollowings.ts index 7a202b9..5454684 100644 --- a/src/nostr/useFollowings.ts +++ b/src/nostr/useFollowings.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { genericEvent } from '@/nostr/event'; import { latestEventQuery } from '@/nostr/query'; diff --git a/src/nostr/useParameterizedReplaceableEvent.ts b/src/nostr/useParameterizedReplaceableEvent.ts index e8e0f9e..6730466 100644 --- a/src/nostr/useParameterizedReplaceableEvent.ts +++ b/src/nostr/useParameterizedReplaceableEvent.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { pickLatestEvent } from '@/nostr/event/comparator'; import { diff --git a/src/nostr/usePool.ts b/src/nostr/usePool.ts index c9d4daa..0c70595 100644 --- a/src/nostr/usePool.ts +++ b/src/nostr/usePool.ts @@ -1,8 +1,8 @@ import { createSignal } from 'solid-js'; -import { SimplePool } from 'nostr-tools'; +import { SimplePool } from 'nostr-tools/pool'; -const [pool] = createSignal(new SimplePool({ eoseSubTimeout: 12000 })); +const [pool] = createSignal(new SimplePool()); const usePool = () => pool; diff --git a/src/nostr/useProfile.ts b/src/nostr/useProfile.ts index 06228f6..655ea9c 100644 --- a/src/nostr/useProfile.ts +++ b/src/nostr/useProfile.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import { Profile, ProfileWithOtherProperties, safeParseProfile } from '@/nostr/event/Profile'; import { latestEventQuery } from '@/nostr/query'; diff --git a/src/nostr/useReactions.ts b/src/nostr/useReactions.ts index 35b507d..2a22eb8 100644 --- a/src/nostr/useReactions.ts +++ b/src/nostr/useReactions.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; import useConfig from '@/core/useConfig'; import { reaction } from '@/nostr/event'; diff --git a/src/nostr/useReposts.ts b/src/nostr/useReposts.ts index 968cb1a..c8e82f8 100644 --- a/src/nostr/useReposts.ts +++ b/src/nostr/useReposts.ts @@ -1,7 +1,7 @@ import { createMemo } from 'solid-js'; import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query'; -import { Event as NostrEvent } from 'nostr-tools'; +import { Event as NostrEvent } from 'nostr-tools/pure'; import useConfig from '@/core/useConfig'; import { eventsQuery } from '@/nostr/query'; diff --git a/src/nostr/useSubscription.ts b/src/nostr/useSubscription.ts index 637bd50..e428f5e 100644 --- a/src/nostr/useSubscription.ts +++ b/src/nostr/useSubscription.ts @@ -1,7 +1,10 @@ import { createSignal, createEffect, onMount, onCleanup, on } from 'solid-js'; import uniqBy from 'lodash/uniqBy'; -import { utils } from 'nostr-tools'; +import { type Filter } from 'nostr-tools/filter'; +import { type SubscribeManyParams } from 'nostr-tools/pool'; +import { type Event as NostrEvent } from 'nostr-tools/pure'; +import { insertEventIntoDescendingList } from 'nostr-tools/utils'; import useConfig from '@/core/useConfig'; import { sortEvents } from '@/nostr/event/comparator'; @@ -9,12 +12,10 @@ import usePool from '@/nostr/usePool'; import useStats from '@/nostr/useStats'; import epoch from '@/utils/epoch'; -import type { Event as NostrEvent, Filter, SubscriptionOptions } from 'nostr-tools'; - export type UseSubscriptionProps = { relayUrls: string[]; filters: Filter[]; - options?: SubscriptionOptions; + options?: SubscribeManyParams; /** * subscribe not only stored events but also new events published after the subscription * default is true @@ -72,7 +73,7 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | null) => { } setEvents((current) => { - const sorted = utils.insertEventIntoDescendingList(current, event).slice(0, limit); + const sorted = insertEventIntoDescendingList(current, event).slice(0, limit); // FIXME なぜか重複して取得される問題があるが一旦uniqByで対処 // https://github.com/syusui-s/rabbit/issues/5 const deduped = uniqBy(sorted, (e) => e.id); @@ -89,8 +90,6 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | null) => { const props = propsProvider(); if (props == null) return; const { relayUrls, filters, options, onEvent, onEOSE, continuous = true } = props; - - const sub = pool().sub(relayUrls, filters, options); let subscribing = true; count += 1; @@ -98,38 +97,45 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | null) => { let eose = false; const storedEvents: NostrEvent[] = []; - sub.on('event', (event: NostrEvent) => { - if (onEvent != null) { - onEvent(event as NostrEvent & { id: string }); - } - if (props.clientEventFilter != null && !props.clientEventFilter(event)) { - return; - } + const sub = pool().subscribeMany( + relayUrls, + filters, + options ?? { + eoseTimeout: 12000, + maxWait: 6000, + onevent: (event: NostrEvent) => { + if (onEvent != null) { + onEvent(event as NostrEvent & { id: string }); + } + if (props.clientEventFilter != null && !props.clientEventFilter(event)) { + return; + } - if (!eose) { - pushed = true; - storedEvents.push(event); - } else { - addEvent(event); - } - }); + if (!eose) { + pushed = true; + storedEvents.push(event); + } else { + addEvent(event); + } + }, + oneose: () => { + if (onEOSE != null) { + onEOSE(); + } - sub.on('eose', () => { - if (onEOSE != null) { - onEOSE(); - } + eose = true; + setEvents(sortEvents(storedEvents)); - eose = true; - setEvents(sortEvents(storedEvents)); - - if (!continuous) { - sub.unsub(); - if (subscribing) { - subscribing = false; - count -= 1; - } - } - }); + if (!continuous) { + sub.close(); + if (subscribing) { + subscribing = false; + count -= 1; + } + } + }, + }, + ); // avoid updating an array too rapidly while this is fetching stored events let updating = false; @@ -150,7 +156,7 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | null) => { onCleanup(() => { console.debug('startSubscription: end'); - sub.unsub(); + sub.close(); if (subscribing) { subscribing = false; count -= 1; diff --git a/src/nostr/useVerification.ts b/src/nostr/useVerification.ts index 040f1cf..308103b 100644 --- a/src/nostr/useVerification.ts +++ b/src/nostr/useVerification.ts @@ -1,15 +1,16 @@ import { createMemo, type Accessor } from 'solid-js'; import { createQuery, type CreateQueryResult } from '@tanstack/solid-query'; -import { nip05, nip19 } from 'nostr-tools'; +import { queryProfile } from 'nostr-tools/nip05'; +import { type ProfilePointer } from 'nostr-tools/nip19'; export type UseVerificationProps = { nip05: string; }; export type UseVerification = { - verification: Accessor; - query: CreateQueryResult; + verification: Accessor; + query: CreateQueryResult; }; const useVerification = (propsProvider: () => UseVerificationProps | null): UseVerification => { @@ -22,7 +23,7 @@ const useVerification = (propsProvider: () => UseVerificationProps | null): UseV const [, currentProps] = queryKey; if (currentProps == null) return Promise.resolve(null); const { nip05: nip05string } = currentProps; - return nip05.queryProfile(nip05string); + return queryProfile(nip05string); }, staleTime: 30 * 60 * 1000, // 30 min cacheTime: 24 * 60 * 60 * 1000, // 24 hour diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 5ab3cd1..7fd5a07 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -25,9 +25,12 @@ const Home: Component = () => { config().relayUrls.map(async (relayUrl) => { try { const relay = await pool().ensureRelay(relayUrl); - relay.on('notice', (msg: string) => { + relay.onnotice = (msg: string) => { console.error(`NOTICE: ${relayUrl}: ${msg}`); - }); + }; + relay.onclose = () => { + console.warn(`CLOSE: ${relayUrl}`); + }; } catch (err) { console.error('ensureRelay failed', err); } diff --git a/src/pages/Permalink.tsx b/src/pages/Permalink.tsx index efee4fb..cf76399 100644 --- a/src/pages/Permalink.tsx +++ b/src/pages/Permalink.tsx @@ -1,7 +1,7 @@ import { createEffect, onMount } from 'solid-js'; import { useNavigate, useParams } from '@solidjs/router'; -import { nip19 } from 'nostr-tools'; +import { decode } from 'nostr-tools/nip19'; import GlobalModal from '@/components/modal/GlobalModal'; import SideBar from '@/components/SideBar'; @@ -25,7 +25,7 @@ const Permalink = () => { onMount(() => { if (params.id != null) { try { - const decoded = nip19.decode(params.id); + const decoded = decode(params.id); if (decoded.type === 'npub') { showProfile(decoded.data); } diff --git a/src/types/nostr.d.ts b/src/types/nostr.d.ts index 51a2595..cbd7752 100644 --- a/src/types/nostr.d.ts +++ b/src/types/nostr.d.ts @@ -1,6 +1,6 @@ // The original code was published under the public domain license (CC0-1.0). // https://gist.github.com/syusui-s/cd5482ddfc83792b54a756759acbda55 -import { type UnsignedEvent, type Event as NostrEvent } from 'nostr-tools'; +import { type UnsignedEvent, type Event as NostrEvent } from 'nostr-tools/pure'; type NostrAPI = { /** returns a public key as hex */ diff --git a/src/utils/npubEncodeFallback.ts b/src/utils/npubEncodeFallback.ts index 5884022..b0fef59 100644 --- a/src/utils/npubEncodeFallback.ts +++ b/src/utils/npubEncodeFallback.ts @@ -1,6 +1,4 @@ -import { nip19 } from 'nostr-tools'; - -const { npubEncode } = nip19; +import { npubEncode } from 'nostr-tools/nip19'; const npubEncodeFallback = (pubkey: string): string => { try { diff --git a/tsconfig.json b/tsconfig.json index 916f13c..bb640aa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "strict": true, "target": "ESNext", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "lib": ["dom", "dom.iterable", "esnext"], "allowSyntheticDefaultImports": true,