diff --git a/.agents/skills/flotilla-architecture/SKILL.md b/.agents/skills/flotilla-architecture/SKILL.md
index b5de1524..7508882e 100644
--- a/.agents/skills/flotilla-architecture/SKILL.md
+++ b/.agents/skills/flotilla-architecture/SKILL.md
@@ -324,7 +324,7 @@ card, and `NoteContentClassified` renders a listing wherever `NoteContent` is us
**Routes.** `src/routes/spaces/[relay]/classifieds/+page.svelte` loads listings and their comments
with `makeFeed` and filters them with the `classifieds.ts` helpers. `[address]/+page.svelte` reads
-one listing with `deriveEvent(address, [url])`.
+one listing with `$events.one(address, [url]).$`.
Articles are composed on a full page (`spaces/[relay]/articles/create`, built by
`makeArticleCreatePath`) instead of in a modal.
diff --git a/.agents/skills/flotilla-model/SKILL.md b/.agents/skills/flotilla-model/SKILL.md
index fc1c53e5..756ab176 100644
--- a/.agents/skills/flotilla-model/SKILL.md
+++ b/.agents/skills/flotilla-model/SKILL.md
@@ -54,8 +54,8 @@ members and pins, the space member list, and roles. Anyone can publish events of
readers must check the author. The welshman collections do: `Rooms` and every
`RelaySignedDerivedPlugin` (`RelayMemberLists`, `RelayRoles`, `RoomPinLists`) drop events whose
author isn't the relay's `self`, and re-check when NIP-11 loads. For a relay-authored kind with no
-plugin, filter `deriveEventsForUrl(url, filters)` on that `self` key yourself rather than reading a
-bare `deriveEventsForUrl`.
+plugin, read `$events.relaySignedForUrl(url, filters)`, which keeps only events signed by that
+`self` key, rather than a bare `$events.forUrl`.
The app signs everything it publishes with the user's own key. Space-wide content with no author of
its own belongs to the space's owner, the pubkey NIP-11 names: featured content
@@ -235,7 +235,7 @@ space it lists or used to list, so each relay hears about joins and leaves. Kind
so `RoomChat` and `publishRoomQuote` publish raw templates through `Thunks`.
Reads are scoped the same way. Request from the space relay (`relays: [url]`, plus `"#h": [h]` for
-a room) and read results with `deriveEventsForUrl(url, filters)`, which uses the tracker to keep
+a room) and read results with `$events.forUrl(url, filters)`, which uses the tracker to keep
only events seen on that relay. A repository-wide query would mix rooms that share an `h` across
relays. `src/app/sync.ts` pulls each space's room state, membership and recent content in the
background; see flotilla-state.
diff --git a/.agents/skills/flotilla-state/SKILL.md b/.agents/skills/flotilla-state/SKILL.md
index 1028beb2..caf82151 100644
--- a/.agents/skills/flotilla-state/SKILL.md
+++ b/.agents/skills/flotilla-state/SKILL.md
@@ -36,7 +36,7 @@ The app is therefore stable for as long as anything under the login gate is moun
| `session` | the persisted `Session` | `undefined` |
| `user` | `User.require($app)`, derived | subscribing or `.get()` throws |
| `usePlugin(Plugin)` | a store holding `$app.use(Plugin)` for the current app | safe |
-| `profiles`, `rooms`, `relays`, `thunks`, … | `usePlugin` for 27 welshman plugins | safe |
+| `profiles`, `rooms`, `relays`, `events`, `thunks`, … | `usePlugin` for 28 welshman plugins | safe |
| `fromApp(read)` | a store that re-reads `read($app)` when the app changes | safe |
| `deriveUserItem(Plugin)` | the signed-in user's entry in a keyed plugin | `undefined` |
| `userSearchRelayUrls` | the user's search relays, or `DEFAULT_SEARCH_RELAYS` | the defaults |
@@ -175,16 +175,19 @@ Events enter `app.repository` from `ingestPolicy` (which calls `tracker.track`,
optimistically. The tracker records which relays each event was seen on, which is what lets
space content be keyed by relay.
-`src/app/repository.ts` wraps the `@welshman/store` derivations in `fromApp`:
+Raw event queries go through welshman's `Events` plugin, exported from `core.ts` as `events`.
+Every method returns a projection over the current app's repository:
-- `deriveEvent`, `deriveEvents`, `deriveEventsById`, `deriveIsDeleted`
-- relay-scoped: `deriveEventsForUrl`, `deriveEventsByIdForUrl`, `deriveEventsByIdByUrl`,
- `getEventsForUrl`
-- `deriveLatestEvent`
+- `one(idOrAddress, relays)` (loads when nothing local matches, keeps deleted events), `byId`,
+ `all`, `asc`, `desc`, `isDeleted`
+- relay-scoped through the tracker: `forUrl`, `byIdForUrl`, `byIdByUrl`, and
+ `relaySignedForUrl`, which keeps only events signed by the relay's NIP-11 `self`
-Use these for raw event queries. Welshman's `Events` plugin has the same surface returning
-projections, and flotilla does not use it. Plugin reads (`get`, `one`, `load`, `index`) are
-documented in welshman-app.
+Components bind `$events.forUrl(url, filters).$`. A `derive*` function called from gated code
+binds `events.get().forUrl(...).$` at call time, and a module-scope store wraps it in
+`fromApp($app => $app.use(Events).byIdByUrl(filters).$)`, as `latestActivityByPath` does.
+`src/app/repository.ts` holds only `deriveLatestEvent`. Plugin reads (`get`, `one`, `load`,
+`index`) are documented in welshman-app.
### Free functions in an app module
@@ -196,7 +199,7 @@ projections and repository derivations:
export const deriveSpaceActionItems = (url: string) =>
derived(
[
- deriveEventsForUrl(url, [{kinds: [REPORT]}]),
+ events.get().forUrl(url, [{kinds: [REPORT]}]).$,
rooms.get().pendingJoins(url).$,
deriveSpacePermissions(url),
],
@@ -424,7 +427,7 @@ store, consumed in components with `$store`.
Take the first answer that fits:
1. **It is an event, or derived from events.** It is already in the repository, or should be.
- Read it with a plugin or an `@app/repository` derivation, and put the domain logic in a
+ Read it with a plugin or the `events` projections, and put the domain logic in a
`derive*` function in the owning app module (`deriveUserRooms`). Don't copy it into a
writable.
2. **It is a keyed collection of one kind, loaded by key.** Write a plugin. A generic kind goes
diff --git a/.agents/skills/flotilla-views/SKILL.md b/.agents/skills/flotilla-views/SKILL.md
index 3d70000d..3907ec4a 100644
--- a/.agents/skills/flotilla-views/SKILL.md
+++ b/.agents/skills/flotilla-views/SKILL.md
@@ -254,7 +254,7 @@ stores, so a component takes the key and looks up the rest: `RoomName` takes `{u
`$rooms.forRoom(url, h)`, `ProfileName` takes `pubkey` and reads `$profiles.display`.
Events are the exception, and 66 components take `event: TrustedEvent`, since the parent already
-holds the event from a feed or a `deriveEvent`. An event prop usually travels with `url`, the
+holds the event from a feed or `$events.one`. An event prop usually travels with `url`, the
relay it lives on, which routes its replies and reactions, and with `context: FeedContext`, the
shared loader below. A component takes a pointer instead only when it has to load the event
itself, as `ContentQuote` does. Anything with neither a store nor an event is passed as its
@@ -281,7 +281,7 @@ param change and lists key by id. A prop that does change while mounted needs `$
## Reading state in a component
Components read plugins through the `usePlugin` stores exported from `src/app/core.ts`
-(`$profiles`, `$relays`, `$rooms`, `$roomLists`, `$network`, `$thunks`, `$deletes`,
+(`$profiles`, `$relays`, `$rooms`, `$roomLists`, `$events`, `$network`, `$thunks`, `$deletes`,
`$relayManagement`, …). `$app.use(X)` covers plugins with no export, such as `Zappers`,
`Pinboards` and `Feeds`; flotilla-state has the rules about which to use where.
@@ -291,6 +291,7 @@ How you bind depends on what the method returns:
@@ -298,7 +299,7 @@ How you bind depends on what the method returns:
```
In a handler, call `.get()` on a projection instead of subscribing. The app modules add `derive*`
-factories over the same data: `deriveEvent` and `deriveEventsById` in `src/app/repository.ts`,
+factories over the same data: `deriveSpaceActionItems` in `src/app/actionItems.ts`,
`deriveSpaceSupportedMethods` in `src/app/management.ts`, `deriveRelayAuthError` in
`src/app/access.ts`. Call them at the top of the script with fixed arguments, and wrap one in
`$derived` only when its arguments change, as the thread page does for filters that wait on the
@@ -316,7 +317,7 @@ data every page needs lives in `src/app/sync.ts`.
`people/[npub]/+page.svelte` does for the profile, relay list, follow, pin, room and messaging
lists before loading the author's outbox with `$network.loadLenient`.
-**A detail page:** `deriveEvent(address, [url])` loads when nothing local matches. While it is
+**A detail page:** `$events.one(address, [url]).$` loads when nothing local matches. While it is
empty, seven pages show a spinner that turns into a failure message:
```svelte
@@ -328,7 +329,7 @@ empty, seven pages show a spinner that turns into a failure message:
```
**Related events:** request them, abort on teardown, and read them back from the repository with
-`deriveEventsAsc(deriveEventsById(filters))`.
+`$events.asc(filters).$`.
```typescript
onMount(() => {
@@ -460,8 +461,8 @@ Rich text uses `makeEditor` from `src/app/editor` with `EditorContent`.
- `flotilla-architecture`: layer rules and exceptions, the `src/app` modules, boot, placement
- `flotilla-state`: plugin stores, `derive*` stores, drafts, settings, thunks and commands
- `flotilla-model`: spaces, rooms, NIP-43/29/86, content kinds, and where events are published
-- `welshman-app`: plugins, projections, `Command`, thunks, `Feeds`
-- `welshman-store`: `deriveEventsById`, `deriveEventsAsc`, the other repository stores
+- `welshman-app`: plugins, projections, `Command`, thunks, `Events`, `Feeds`
+- `welshman-store`: `deriveEventsById`, `deriveEventsAsc`, the repository stores under `Events`
- `welshman-domain`: the readers and writers behind `reader` and `writer`
- `welshman-feeds`: `FeedController`, still used by `ProfileFeed`
- `welshman-editor`: the composer behind `makeEditor`
diff --git a/src/app/actionItems.ts b/src/app/actionItems.ts
index 379ba029..c85c2072 100644
--- a/src/app/actionItems.ts
+++ b/src/app/actionItems.ts
@@ -1,8 +1,7 @@
import {derived} from "svelte/store"
import {REPORT, sortEventsDesc} from "@welshman/util"
-import {rooms} from "@app/core"
+import {events, rooms} from "@app/core"
import {deriveSpacePermissions} from "@app/management"
-import {deriveEventsForUrl} from "@app/repository"
// Action items (admin review queue)
@@ -10,7 +9,7 @@ import {deriveEventsForUrl} from "@app/repository"
export const deriveSpaceActionItems = (url: string) =>
derived(
[
- deriveEventsForUrl(url, [{kinds: [REPORT]}]),
+ events.get().forUrl(url, [{kinds: [REPORT]}]).$,
rooms.get().pendingJoins(url).$,
deriveSpacePermissions(url),
],
diff --git a/src/app/calendar.ts b/src/app/calendar.ts
index eee59e5c..76566224 100644
--- a/src/app/calendar.ts
+++ b/src/app/calendar.ts
@@ -14,8 +14,7 @@ import type {TrustedEvent} from "@welshman/util"
import {CalendarRsvp, TimeEvent} from "@welshman/domain"
import type {RsvpStatus} from "@welshman/domain"
import {synced} from "@welshman/store"
-import {deletes, reader, relays, thunks, writer} from "@app/core"
-import {deriveEvents} from "@app/repository"
+import {deletes, events, reader, relays, thunks, writer} from "@app/core"
import {toSpace} from "@app/rooms"
import {kv} from "@app/storage"
@@ -237,7 +236,7 @@ export const makeRsvpFilter = (event: TrustedEvent) => ({
"#a": [getAddress(event)],
})
-export const deriveRsvps = (event: TrustedEvent) => deriveEvents([makeRsvpFilter(event)])
+export const deriveRsvps = (event: TrustedEvent) => events.get().desc([makeRsvpFilter(event)]).$
export const isAttending = (status?: RsvpStatus) => status === "accepted" || status === "tentative"
diff --git a/src/app/call.ts b/src/app/call.ts
index f9da559e..d2ba972b 100644
--- a/src/app/call.ts
+++ b/src/app/call.ts
@@ -5,8 +5,7 @@ import {deriveDeduplicated} from "@welshman/store"
import {makeRoomKey} from "@welshman/app"
import type {Room} from "@welshman/app"
import type {Room as LiveKitRoom} from "livekit-client"
-import {network} from "@app/core"
-import {deriveEventsForUrl} from "@app/repository"
+import {events, network} from "@app/core"
export const LIVEKIT_PARTICIPANTS = 39004
@@ -304,7 +303,7 @@ export const deriveCallParticipants = (url: string, h: string) =>
participantMediaState,
callTargetRoom,
deriveDeduplicated(
- deriveEventsForUrl(url, [{kinds: [LIVEKIT_PARTICIPANTS], "#d": [h]}]),
+ events.get().forUrl(url, [{kinds: [LIVEKIT_PARTICIPANTS], "#d": [h]}]).$,
events => first(sortEventsDesc(events)),
),
],
diff --git a/src/app/components/ArticleActions.svelte b/src/app/components/ArticleActions.svelte
index 8ce9ab89..85c0f311 100644
--- a/src/app/components/ArticleActions.svelte
+++ b/src/app/components/ArticleActions.svelte
@@ -11,8 +11,7 @@
import EventActivity from "@app/components/EventActivity.svelte"
import EventActions from "@app/components/EventActions.svelte"
import EventActionBar from "@app/components/EventActionBar.svelte"
- import {reader} from "@app/core"
- import {deriveIsDeleted} from "@app/repository"
+ import {events, reader} from "@app/core"
import {makeSpacePath} from "@app/routes"
type Props = {
@@ -30,7 +29,7 @@
const article = $derived(reader(Article)(event))
const h = $derived(article.room())
const topics = $derived(article.topics())
- const deleted = $derived(deriveIsDeleted(event))
+ const deleted = $derived($events.isDeleted(event).$)
const deleteReaction = (reaction: TrustedEvent) => retractReaction(reaction, {url, h})
diff --git a/src/app/components/ArticleAuthorSidebar.svelte b/src/app/components/ArticleAuthorSidebar.svelte
index fa9db59e..1f935f9c 100644
--- a/src/app/components/ArticleAuthorSidebar.svelte
+++ b/src/app/components/ArticleAuthorSidebar.svelte
@@ -9,8 +9,7 @@
import Profile from "@app/components/Profile.svelte"
import ProfileName from "@app/components/ProfileName.svelte"
import ProfileAbout from "@app/components/ProfileAbout.svelte"
- import {network, reader} from "@app/core"
- import {deriveEventsForUrl} from "@app/repository"
+ import {events, network, reader} from "@app/core"
import {displayReadingTime} from "@app/articles"
import {makeArticlePath} from "@app/routes"
@@ -24,15 +23,15 @@
const MAX_ARTICLES = 6
const filters = [{kinds: [LONG_FORM], authors: [event.pubkey], limit: 20}]
- const events = deriveEventsForUrl(url, filters)
+ const articles = $events.forUrl(url, filters).$
const address = getAddress(event)
- const articleCount = $derived($events.length)
+ const articleCount = $derived($articles.length)
const others = $derived(
sortBy(
e => -reader(Article)(e).publishedAt(),
- $events.filter(e => getAddress(e) !== address),
+ $articles.filter(e => getAddress(e) !== address),
).slice(0, MAX_ARTICLES),
)
diff --git a/src/app/components/ContentQuote.svelte b/src/app/components/ContentQuote.svelte
index ca0ff1ee..9768a7e7 100644
--- a/src/app/components/ContentQuote.svelte
+++ b/src/app/components/ContentQuote.svelte
@@ -17,8 +17,7 @@
import NoteCard from "@app/components/NoteCard.svelte"
import NoteContent from "@app/components/NoteContent.svelte"
import NoteContentMinimal from "@app/components/NoteContentMinimal.svelte"
- import {network, router} from "@app/core"
- import {deriveEvent} from "@app/repository"
+ import {events, network, router} from "@app/core"
import {entityLink} from "@app/env"
import {goToEvent} from "@app/routes"
@@ -39,7 +38,7 @@
const mergedRelays = writable(hints)
- const quote = deriveEvent(idOrAddress, hints)
+ const quote = $events.one(idOrAddress, hints).$
// Whoever quoted the event must have seen it, so the quoting event's relays are asked too.
$router.resolver
diff --git a/src/app/components/EventComments.svelte b/src/app/components/EventComments.svelte
index 7fc9d143..173c6ca6 100644
--- a/src/app/components/EventComments.svelte
+++ b/src/app/components/EventComments.svelte
@@ -3,15 +3,13 @@
import {removeUndefined} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
import {getCommentFiltersForRoot} from "@welshman/util"
- import {deriveEventsAsc} from "@welshman/store"
import Reply from "@assets/icons/reply-2.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import CommentTree from "@app/components/CommentTree.svelte"
import type {FeedContext} from "@app/feeds"
import CommentCompose from "@app/components/CommentCompose.svelte"
- import {network} from "@app/core"
- import {deriveEventsById} from "@app/repository"
+ import {events, network} from "@app/core"
import {buildCommentTree} from "@app/social"
type Props = {
@@ -24,7 +22,7 @@
const relays = removeUndefined([url])
const filters = getCommentFiltersForRoot([event])
- const comments = deriveEventsAsc(deriveEventsById(filters))
+ const comments = $events.asc(filters).$
const nodes = $derived(buildCommentTree(event, $comments))
diff --git a/src/app/components/NoteContentMinimalPoll.svelte b/src/app/components/NoteContentMinimalPoll.svelte
index 7de6b942..1bdb1957 100644
--- a/src/app/components/NoteContentMinimalPoll.svelte
+++ b/src/app/components/NoteContentMinimalPoll.svelte
@@ -3,12 +3,11 @@
import {POLL_RESPONSE} from "@welshman/util"
import {Poll} from "@welshman/domain"
import ContentMinimal from "@app/components/ContentMinimal.svelte"
- import {reader} from "@app/core"
- import {deriveEvents} from "@app/repository"
+ import {events, reader} from "@app/core"
const props: ComponentProps = $props()
- const responses = deriveEvents([{kinds: [POLL_RESPONSE], "#e": [props.event.id]}])
+ const responses = $events.desc([{kinds: [POLL_RESPONSE], "#e": [props.event.id]}]).$
const voters = $derived(reader(Poll)(props.event).results($responses).voters)
diff --git a/src/app/components/PinContentEvent.svelte b/src/app/components/PinContentEvent.svelte
index 5a3f5159..44fa98b6 100644
--- a/src/app/components/PinContentEvent.svelte
+++ b/src/app/components/PinContentEvent.svelte
@@ -2,8 +2,8 @@
import {onDestroy} from "svelte"
import Spinner from "@lib/components/Spinner.svelte"
import NoteItem from "@app/components/NoteItem.svelte"
+ import {events} from "@app/core"
import {makeFeedContext} from "@app/feeds"
- import {deriveEvent} from "@app/repository"
type Props = {
url?: string
@@ -13,7 +13,7 @@
const {url, value, relays}: Props = $props()
- const event = deriveEvent(value, relays)
+ const event = $events.one(value, relays).$
const context = makeFeedContext({relays})
onDestroy(context.cleanup)
diff --git a/src/app/components/PinboardSelect.svelte b/src/app/components/PinboardSelect.svelte
index 226739e1..7cf17b49 100644
--- a/src/app/components/PinboardSelect.svelte
+++ b/src/app/components/PinboardSelect.svelte
@@ -15,9 +15,8 @@
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
import RelayName from "@app/components/RelayName.svelte"
import PinAdd from "@app/components/PinAdd.svelte"
- import {reader} from "@app/core"
+ import {events, reader} from "@app/core"
import {eventToReference} from "@app/pinboards"
- import {deriveEventsForUrl} from "@app/repository"
import {makeSpacePath} from "@app/routes"
import {pushModal} from "@app/modal"
@@ -28,8 +27,8 @@
const {url, event}: Props = $props()
- const boards = derived(deriveEventsForUrl(url, [{kinds: [PINBOARD]}]), $events =>
- $events.map(reader(Pinboard)),
+ const boards = derived($events.forUrl(url, [{kinds: [PINBOARD]}]).$, $pinboards =>
+ $pinboards.map(reader(Pinboard)),
)
const reference = eventToReference(event)
diff --git a/src/app/components/PollVotes.svelte b/src/app/components/PollVotes.svelte
index 30355ed2..253b16be 100644
--- a/src/app/components/PollVotes.svelte
+++ b/src/app/components/PollVotes.svelte
@@ -6,8 +6,7 @@
import {Poll, PollResponse} from "@welshman/domain"
import type {Thunk} from "@welshman/app"
import PollOption from "@app/components/PollOption.svelte"
- import {command, reader, thunks, user, writer} from "@app/core"
- import {deriveEvents} from "@app/repository"
+ import {command, events, reader, thunks, user, writer} from "@app/core"
type Props = {
url: string
@@ -16,7 +15,7 @@
const {url, event}: Props = $props()
- const responses = deriveEvents([{kinds: [POLL_RESPONSE], "#e": [event.id]}])
+ const responses = $events.desc([{kinds: [POLL_RESPONSE], "#e": [event.id]}]).$
const getOwnResponse = (responses: TrustedEvent[]) => {
let latest: TrustedEvent | undefined
diff --git a/src/app/components/ReportDetails.svelte b/src/app/components/ReportDetails.svelte
index f84f6653..23b6530d 100644
--- a/src/app/components/ReportDetails.svelte
+++ b/src/app/components/ReportDetails.svelte
@@ -8,8 +8,8 @@
import ModalBody from "@lib/components/ModalBody.svelte"
import Button from "@lib/components/Button.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte"
- import {deriveEventsById} from "@app/repository"
import ReportItem from "@app/components/ReportItem.svelte"
+ import {events} from "@app/core"
type Props = {
url: string
@@ -18,7 +18,7 @@
const {url, event}: Props = $props()
- const reports = deriveEventsById([{kinds: [REPORT], "#e": [event.id]}])
+ const reports = $events.byId([{kinds: [REPORT], "#e": [event.id]}]).$
const back = () => history.back()
diff --git a/src/app/components/RoomItem.svelte b/src/app/components/RoomItem.svelte
index aa7becca..764aeec3 100644
--- a/src/app/components/RoomItem.svelte
+++ b/src/app/components/RoomItem.svelte
@@ -32,12 +32,11 @@
import RoomItemMenuButton from "@app/components/RoomItemMenuButton.svelte"
import RoomItemMenuMobile from "@app/components/RoomItemMenuMobile.svelte"
import RoomItemContent from "@app/components/RoomItemContent.svelte"
- import {profiles, thunks, user} from "@app/core"
+ import {events, profiles, thunks, user} from "@app/core"
import {noThunks, thunksByEventId} from "@app/thunks"
import {colorFor} from "@app/theme"
import {ENABLE_ZAPS} from "@app/env"
import type {FeedContext} from "@app/feeds"
- import {deriveEvent, deriveEventsForUrl} from "@app/repository"
import {highlightedEvent, makeContentPath, makeThreadPath} from "@app/routes"
import {pushModal} from "@app/modal"
@@ -70,16 +69,16 @@
// A message that is nothing but a reference renders as the event it quotes.
const isQuoteOnly = event.content.trim().split(/\s/).length === 1
const quote = isQuoteOnly ? getContentQuote(event.content) : undefined
- const innerEvent = quote ? deriveEvent(quote.value, [url]) : readable(undefined)
+ const innerEvent = quote ? $events.one(quote.value, [url]).$ : readable(undefined)
const innerComments = $derived(
- $innerEvent ? deriveEventsForUrl(url, getCommentFiltersForParent([$innerEvent])) : readable([]),
+ $innerEvent ? $events.forUrl(url, getCommentFiltersForParent([$innerEvent])).$ : readable([]),
)
const path = $derived(
$innerEvent && makeContentPath(url, $innerEvent.kind, getIdOrAddress($innerEvent)),
)
- const threads = deriveEventsForUrl(url, [{kinds: [THREAD], "#q": [event.id]}])
+ const threads = $events.forUrl(url, [{kinds: [THREAD], "#q": [event.id]}]).$
const commenterDisplays = $derived(
deriveDisplaysByPubkey(uniq($innerComments.map(e => e.pubkey)), url),
diff --git a/src/app/components/SearchBody.svelte b/src/app/components/SearchBody.svelte
index 3c1eca16..057fd736 100644
--- a/src/app/components/SearchBody.svelte
+++ b/src/app/components/SearchBody.svelte
@@ -14,8 +14,7 @@
import PeopleItem from "@app/components/PeopleItem.svelte"
import NoteCard from "@app/components/NoteCard.svelte"
import NoteContentMinimal from "@app/components/NoteContentMinimal.svelte"
- import {getEventsForUrl} from "@app/repository"
- import {network, profiles} from "@app/core"
+ import {events, network, profiles} from "@app/core"
import {popModal} from "@app/modal"
import {pushToast} from "@app/toast"
import {goToEvent} from "@app/routes"
@@ -52,7 +51,7 @@
results = sortEventsDesc(
uniqBy(
(e: TrustedEvent) => e.id,
- relays.flatMap(relay => Array.from(getEventsForUrl(relay, filters))),
+ relays.flatMap(relay => events.get().forUrl(relay, filters).get()),
),
)
diff --git a/src/app/components/SpaceMembersSummary.svelte b/src/app/components/SpaceMembersSummary.svelte
index 92eadc9b..cbfc8525 100644
--- a/src/app/components/SpaceMembersSummary.svelte
+++ b/src/app/components/SpaceMembersSummary.svelte
@@ -6,8 +6,7 @@
import Icon from "@lib/components/Icon.svelte"
import Link from "@lib/components/Link.svelte"
import Profile from "@app/components/Profile.svelte"
- import {relayMemberLists, relays} from "@app/core"
- import {deriveEventsForUrl} from "@app/repository"
+ import {events, relayMemberLists, relays} from "@app/core"
import {makeSpacePath} from "@app/routes"
type Props = {
@@ -18,7 +17,7 @@
const relay = $relays.one(url)
const members = $relayMemberLists.forUrl(url)
- const memberEvents = deriveEventsForUrl(url, [{kinds: [RELAY_ADD_MEMBER, RELAY_JOIN]}])
+ const memberEvents = $events.forUrl(url, [{kinds: [RELAY_ADD_MEMBER, RELAY_JOIN]}]).$
const admins = $derived($relay?.pubkey ? [$relay.pubkey] : [])
diff --git a/src/app/components/SpaceMenuNavItems.svelte b/src/app/components/SpaceMenuNavItems.svelte
index ef30fea3..002f1019 100644
--- a/src/app/components/SpaceMenuNavItems.svelte
+++ b/src/app/components/SpaceMenuNavItems.svelte
@@ -17,10 +17,9 @@
import Icon from "@lib/components/Icon.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import SpaceSearch from "@app/components/SpaceSearch.svelte"
- import {relays} from "@app/core"
+ import {events, relays} from "@app/core"
import {ENABLE_ZAPS} from "@app/env"
import {CONTENT_KINDS} from "@app/content"
- import {deriveEventsForUrl} from "@app/repository"
import {makeSpacePath} from "@app/routes"
import {allNotifications, notifications} from "@app/notifications"
import {pushModal} from "@app/modal"
@@ -46,8 +45,8 @@
const cachedKinds: number[] = getJson(spaceKindsKey) ?? []
const spaceKinds = deriveDeduplicatedByValue(
- deriveEventsForUrl(url, [{kinds: CONTENT_KINDS}]),
- $events => new Set([...cachedKinds, ...$events.map(e => e.kind)]),
+ $events.forUrl(url, [{kinds: CONTENT_KINDS}]).$,
+ $content => new Set([...cachedKinds, ...$content.map(e => e.kind)]),
)
// A comment can name content this space doesn't have, and it counts toward the space either way.
diff --git a/src/app/components/SpaceReports.svelte b/src/app/components/SpaceReports.svelte
index 9d9af14e..54d045ea 100644
--- a/src/app/components/SpaceReports.svelte
+++ b/src/app/components/SpaceReports.svelte
@@ -11,7 +11,7 @@
import ModalFooter from "@lib/components/ModalFooter.svelte"
import ReportItem from "@app/components/ReportItem.svelte"
import RelayName from "@app/components/RelayName.svelte"
- import {deriveEventsForUrl} from "@app/repository"
+ import {events} from "@app/core"
interface Props {
url: string
@@ -19,7 +19,7 @@
const {url}: Props = $props()
- const reports = deriveEventsForUrl(url, [{kinds: [REPORT]}])
+ const reports = $events.forUrl(url, [{kinds: [REPORT]}]).$
const back = () => history.back()
diff --git a/src/app/core.ts b/src/app/core.ts
index 6ee77bae..9a5ef98d 100644
--- a/src/app/core.ts
+++ b/src/app/core.ts
@@ -10,6 +10,7 @@ import {
BlossomServerLists,
Deletes,
Domain,
+ Events,
FollowLists,
Handles,
Logger,
@@ -130,6 +131,7 @@ export const blockedRelayLists = usePlugin(BlockedRelayLists)
export const blossomServerLists = usePlugin(BlossomServerLists)
export const deletes = usePlugin(Deletes)
export const domain = usePlugin(Domain)
+export const events = usePlugin(Events)
export const followLists = usePlugin(FollowLists)
export const handles = usePlugin(Handles)
export const logger = usePlugin(Logger)
diff --git a/src/app/featured.ts b/src/app/featured.ts
index d081282d..46ef50f0 100644
--- a/src/app/featured.ts
+++ b/src/app/featured.ts
@@ -2,8 +2,7 @@ import {derived} from "svelte/store"
import {APP_DATA, sortEventsDesc, tagSpec, tagValues} from "@welshman/util"
import {AppData} from "@welshman/domain"
import {Relays, publish} from "@welshman/app"
-import {command, fromApp, writer} from "@app/core"
-import {deriveEventsForUrl} from "@app/repository"
+import {command, events, fromApp, writer} from "@app/core"
import {toSpace} from "@app/rooms"
// NIP-78 app data from the pubkey the space's NIP-11 names, one ["content", ] tag per entry.
@@ -13,7 +12,7 @@ export const deriveFeaturedContent = (url: string) =>
derived(
[
fromApp($app => $app.use(Relays).one(url)),
- deriveEventsForUrl(url, [{kinds: [APP_DATA], "#d": [FEATURED_CONTENT_D]}]),
+ events.get().forUrl(url, [{kinds: [APP_DATA], "#d": [FEATURED_CONTENT_D]}]).$,
],
([$relay, $events]) => {
const [event] = sortEventsDesc($events.filter(e => e.pubkey === $relay?.pubkey))
diff --git a/src/app/feeds.ts b/src/app/feeds.ts
index 40b95f93..ea53027a 100644
--- a/src/app/feeds.ts
+++ b/src/app/feeds.ts
@@ -30,6 +30,7 @@ import {
tagValues,
} from "@welshman/util"
import {Comment, TimeEvent} from "@welshman/domain"
+import {Events} from "@welshman/app"
import type {Maybe} from "@welshman/lib"
import type {Filter, TrustedEvent} from "@welshman/util"
import {mergeRepositoryUpdates} from "@welshman/net"
@@ -39,7 +40,6 @@ import type {ScrollerOpts} from "@lib/html"
import {daysBetween} from "@lib/util"
import {EVENT_CONTEXT_KINDS, REACTION_KINDS} from "@app/content"
import {app, network, reader} from "@app/core"
-import {getEventsForUrl} from "@app/repository"
const noEvents: TrustedEvent[] = []
@@ -661,7 +661,7 @@ export const makeFeed = ({
// What the repository already holds is an answer too, so a page of it renders before any relay replies.
const stored = relays.map(url =>
- Array.from(getEventsForUrl(url, filters)).sort(compareEventsAsc).slice(-PAGE_SIZE),
+ app.get().use(Events).forUrl(url, filters).get().sort(compareEventsAsc).slice(-PAGE_SIZE),
)
if (stored.every(page => page.length > 0)) {
@@ -712,7 +712,7 @@ export const makeCalendarFeed = ({
const events = writable(
uniqBy(
e => e.id,
- relays.flatMap(url => Array.from(getEventsForUrl(url, filters))),
+ relays.flatMap(url => app.get().use(Events).forUrl(url, filters).get()),
).sort(compareByStart),
)
diff --git a/src/app/management.ts b/src/app/management.ts
index 31eca984..6422c3bf 100644
--- a/src/app/management.ts
+++ b/src/app/management.ts
@@ -3,8 +3,7 @@ import {ago, MINUTE, now, simpleCache} from "@welshman/lib"
import {ROOM_CREATE_PERMISSION, hexTags, tagValues} from "@welshman/util"
import {RelayManagement, Relays} from "@welshman/app"
import type {IApp} from "@welshman/app"
-import {fromApp, usePlugin, user} from "@app/core"
-import {deriveEventsForUrl} from "@app/repository"
+import {events, fromApp, usePlugin, user} from "@app/core"
// `supportedmethods` answers for the pubkey that signed the request, so this catalog is the client's.
export const MANAGEMENT_METHOD_GROUPS = [
@@ -221,7 +220,7 @@ export const deriveUserCanCreateRoom = (url: string) =>
derived(
[
user,
- deriveEventsForUrl(url, [{kinds: [ROOM_CREATE_PERMISSION]}]),
+ events.get().forUrl(url, [{kinds: [ROOM_CREATE_PERMISSION]}]).$,
deriveUserIsSpaceStaff(url),
],
([$user, $events, $isStaff]) =>
diff --git a/src/app/notifications.ts b/src/app/notifications.ts
index 722206d9..0cb2d821 100644
--- a/src/app/notifications.ts
+++ b/src/app/notifications.ts
@@ -15,8 +15,7 @@ import {
} from "@welshman/util"
import {Comment} from "@welshman/domain"
import {synced, throttled, withGetter} from "@welshman/store"
-import {Relays, RoomLists} from "@welshman/app"
-import {deriveEventsByIdByUrl} from "@app/repository"
+import {Events, Relays, RoomLists} from "@welshman/app"
import {app, fromApp, reader} from "@app/core"
import {makeRoomPath, makeSpaceChatPath, makeChatPath, makeContentPath} from "@app/routes"
import {CONTENT_KINDS, makeCommentFilter} from "@app/content"
@@ -236,10 +235,13 @@ export const latestActivityByPath = derived(
chatsById,
fromApp($app => $app.use(Relays).index.$),
fromApp($app => $app.use(RoomLists).index.$),
- deriveEventsByIdByUrl([
- {kinds: [MESSAGE, ...CONTENT_KINDS]},
- makeCommentFilter(CONTENT_KINDS),
- ]),
+ fromApp(
+ $app =>
+ $app
+ .use(Events)
+ .byIdByUrl([{kinds: [MESSAGE, ...CONTENT_KINDS]}, makeCommentFilter(CONTENT_KINDS)])
+ .$,
+ ),
userSettingsValues,
],
identity,
diff --git a/src/app/pins.ts b/src/app/pins.ts
index fd9fe9a2..6aa3979d 100644
--- a/src/app/pins.ts
+++ b/src/app/pins.ts
@@ -2,8 +2,7 @@ import {derived} from "svelte/store"
import type {Readable} from "svelte/store"
import {getIdFilters, outbox} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
-import {network, pinLists, router} from "@app/core"
-import {deriveEvents} from "@app/repository"
+import {events, network, pinLists, router} from "@app/core"
export const derivePinnedEvents = (pubkey: string): Readable =>
derived(
@@ -22,7 +21,7 @@ export const derivePinnedEvents = (pubkey: string): Readable =>
network.get().loadLenient({relays: $relays, filters, signal: controller.signal}),
)
- const unsubscribe = deriveEvents(filters).subscribe(set)
+ const unsubscribe = events.get().desc(filters).$.subscribe(set)
return () => {
controller.abort()
diff --git a/src/app/repository.ts b/src/app/repository.ts
index 85611cc6..a7061133 100644
--- a/src/app/repository.ts
+++ b/src/app/repository.ts
@@ -3,61 +3,8 @@ import type {Unsubscriber} from "svelte/store"
import {first, on} from "@welshman/lib"
import type {Maybe} from "@welshman/lib"
import {sortEventsDesc} from "@welshman/util"
-import type {Filter, TrustedEvent} from "@welshman/util"
-import * as store from "@welshman/store"
-import {Network} from "@welshman/app"
-import {app, fromApp} from "@app/core"
-
-// Events
-
-export const deriveEvent = (idOrAddress: string, relays: string[] = []) =>
- fromApp($app =>
- store.makeDeriveEvent({
- repository: $app.repository,
- includeDeleted: true,
- onDerive: (filters: Filter[], hints: string[]) =>
- $app.use(Network).loadLenient({filters, relays: hints}),
- })(idOrAddress, relays),
- )
-
-export const deriveEventsById = (filters: Filter[] = [{}]) =>
- fromApp($app => store.deriveEventsById({repository: $app.repository, filters}))
-
-export const deriveEvents = (filters: Filter[] = [{}]) =>
- store.deriveEventsDesc(deriveEventsById(filters))
-
-export const deriveIsDeleted = (event: TrustedEvent) =>
- fromApp($app => store.deriveIsDeleted($app.repository, event))
-
-// Events on a relay
-
-export const getEventsForUrl = (url: string, filters: Filter[] = [{}]) =>
- store
- .getEventsByIdForUrl({
- url,
- filters,
- tracker: app.get().tracker,
- repository: app.get().repository,
- })
- .values()
-
-export const deriveEventsByIdForUrl = (url: string, filters: Filter[] = [{}]) =>
- fromApp($app =>
- store.deriveEventsByIdForUrl({
- url,
- filters,
- tracker: $app.tracker,
- repository: $app.repository,
- }),
- )
-
-export const deriveEventsForUrl = (url: string, filters: Filter[] = [{}]) =>
- store.deriveArray(deriveEventsByIdForUrl(url, filters))
-
-export const deriveEventsByIdByUrl = (filters: Filter[] = [{}]) =>
- fromApp($app =>
- store.deriveEventsByIdByUrl({filters, tracker: $app.tracker, repository: $app.repository}),
- )
+import type {TrustedEvent} from "@welshman/util"
+import {app} from "@app/core"
// The most recent event held from one author.
diff --git a/src/app/roomPins.ts b/src/app/roomPins.ts
index 3d04e1d1..57ea5617 100644
--- a/src/app/roomPins.ts
+++ b/src/app/roomPins.ts
@@ -2,8 +2,7 @@ import {derived, readable} from "svelte/store"
import type {Readable} from "svelte/store"
import {getIdFilters, getIdOrAddress} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
-import {network, roomPinLists} from "@app/core"
-import {deriveEventsForUrl} from "@app/repository"
+import {events, network, roomPinLists} from "@app/core"
export const deriveRoomPinnedEvents = (url: string, h: string): Readable =>
readable([], set => {
@@ -24,22 +23,25 @@ export const deriveRoomPinnedEvents = (url: string, h: string): Readable {
- const byPin = new Map(
- $events.flatMap(event => [
- [event.id, event],
- [getIdOrAddress(event), event],
- ]),
- )
+ return events
+ .get()
+ .forUrl(url, filters)
+ .$.subscribe($events => {
+ const byPin = new Map(
+ $events.flatMap(event => [
+ [event.id, event],
+ [getIdOrAddress(event), event],
+ ]),
+ )
- setEvents(
- $pins.flatMap(pin => {
- const event = byPin.get(pin)
+ setEvents(
+ $pins.flatMap(pin => {
+ const event = byPin.get(pin)
- return event ? [event] : []
- }),
- )
- })
+ return event ? [event] : []
+ }),
+ )
+ })
},
).subscribe(set)
diff --git a/src/routes/spaces/[relay]/articles/[address]/+page.svelte b/src/routes/spaces/[relay]/articles/[address]/+page.svelte
index 41c009c4..abd42136 100644
--- a/src/routes/spaces/[relay]/articles/[address]/+page.svelte
+++ b/src/routes/spaces/[relay]/articles/[address]/+page.svelte
@@ -16,8 +16,7 @@
import EventComments from "@app/components/EventComments.svelte"
import EventMenu from "@app/components/EventMenu.svelte"
import ReadingProgress from "@app/components/ReadingProgress.svelte"
- import {reader} from "@app/core"
- import {deriveEvent} from "@app/repository"
+ import {events, reader} from "@app/core"
import {makeFeedContext} from "@app/feeds"
import {decodeRelay} from "@app/relays"
import {displayReadingTime} from "@app/articles"
@@ -29,7 +28,7 @@
const {relay, address} = params
const url = decodeRelay(relay)
const context = makeFeedContext({relays: [url]})
- const event = deriveEvent(address, [url])
+ const event = $events.one(address, [url]).$
const article = derived(event, $event => ($event ? reader(Article)($event) : undefined))
const h = $derived($article?.room())
const topics = $derived(uniq($article?.topics() ?? []))
diff --git a/src/routes/spaces/[relay]/calendar/[address]/+page.svelte b/src/routes/spaces/[relay]/calendar/[address]/+page.svelte
index 349544af..1a8b7cb1 100644
--- a/src/routes/spaces/[relay]/calendar/[address]/+page.svelte
+++ b/src/routes/spaces/[relay]/calendar/[address]/+page.svelte
@@ -23,8 +23,7 @@
import CalendarEventPeople from "@app/components/CalendarEventPeople.svelte"
import CalendarRsvp from "@app/components/CalendarRsvp.svelte"
import {deriveRsvps, getRsvpsByStatus, makeRsvpFilter} from "@app/calendar"
- import {network, reader} from "@app/core"
- import {deriveEvent, deriveEvents} from "@app/repository"
+ import {events, network, reader} from "@app/core"
import {makeFeedContext} from "@app/feeds"
import {decodeRelay} from "@app/relays"
import type {PageProps} from "./$types"
@@ -34,10 +33,10 @@
const {relay, address} = params
const url = decodeRelay(relay)
const context = makeFeedContext({relays: [url]})
- const event = deriveEvent(address, [url])
+ const event = $events.one(address, [url]).$
const timeEvent = derived(event, $event => ($event ? reader(TimeEvent)($event) : undefined))
const filters = $derived($event ? getCommentFiltersForRoot([$event]) : [])
- const replies = $derived(deriveEvents(filters))
+ const replies = $derived($events.desc(filters).$)
const rsvps = $derived($event ? deriveRsvps($event) : readable([]))
const people = $derived(getRsvpsByStatus($rsvps))
diff --git a/src/routes/spaces/[relay]/classifieds/[address]/+page.svelte b/src/routes/spaces/[relay]/classifieds/[address]/+page.svelte
index 813020d1..6f6ac8d0 100644
--- a/src/routes/spaces/[relay]/classifieds/[address]/+page.svelte
+++ b/src/routes/spaces/[relay]/classifieds/[address]/+page.svelte
@@ -10,8 +10,7 @@
import NoteCard from "@app/components/NoteCard.svelte"
import ClassifiedActions from "@app/components/ClassifiedActions.svelte"
import EventComments from "@app/components/EventComments.svelte"
- import {reader} from "@app/core"
- import {deriveEvent} from "@app/repository"
+ import {events, reader} from "@app/core"
import {makeFeedContext} from "@app/feeds"
import {decodeRelay} from "@app/relays"
import type {PageProps} from "./$types"
@@ -21,7 +20,7 @@
const {relay, address} = params
const url = decodeRelay(relay)
const context = makeFeedContext({relays: [url]})
- const event = deriveEvent(address, [url])
+ const event = $events.one(address, [url]).$
const classified = derived(event, $event => ($event ? reader(Classified)($event) : undefined))
const back = () => history.back()
diff --git a/src/routes/spaces/[relay]/goals/[id]/+page.svelte b/src/routes/spaces/[relay]/goals/[id]/+page.svelte
index b8f1866f..d49c8314 100644
--- a/src/routes/spaces/[relay]/goals/[id]/+page.svelte
+++ b/src/routes/spaces/[relay]/goals/[id]/+page.svelte
@@ -18,10 +18,9 @@
import GoalStatus from "@app/components/GoalStatus.svelte"
import GoalSupporters from "@app/components/GoalSupporters.svelte"
import EventComments from "@app/components/EventComments.svelte"
- import {reader} from "@app/core"
+ import {events, reader} from "@app/core"
import {ENABLE_ZAPS} from "@app/env"
import {deriveGoalProgress} from "@app/goals"
- import {deriveEvent} from "@app/repository"
import {makeFeedContext} from "@app/feeds"
import {decodeRelay} from "@app/relays"
import type {PageProps} from "./$types"
@@ -31,7 +30,7 @@
const {relay, id} = params
const url = decodeRelay(relay)
const context = makeFeedContext({relays: [url]})
- const event = deriveEvent(id, [url])
+ const event = $events.one(id, [url]).$
const goal = derived(event, $event => ($event ? reader(ZapGoal)($event) : undefined))
const progress = $derived($event ? deriveGoalProgress($event, url) : undefined)
const remaining = $derived($progress ? Math.max(0, $progress.target - $progress.raised) : 0)
diff --git a/src/routes/spaces/[relay]/library/+page.svelte b/src/routes/spaces/[relay]/library/+page.svelte
index 8df067e8..abb7025a 100644
--- a/src/routes/spaces/[relay]/library/+page.svelte
+++ b/src/routes/spaces/[relay]/library/+page.svelte
@@ -21,9 +21,8 @@
import PinAdd from "@app/components/PinAdd.svelte"
import PinboardItem from "@app/components/PinboardItem.svelte"
import PinboardEdit from "@app/components/PinboardEdit.svelte"
- import {app, network, reader} from "@app/core"
+ import {app, events, network, reader} from "@app/core"
import {decodeRelay} from "@app/relays"
- import {deriveEventsForUrl} from "@app/repository"
import {makeLibraryPath} from "@app/routes"
import {pushModal} from "@app/modal"
import type {PageProps} from "./$types"
@@ -36,8 +35,8 @@
let loading = $state(true)
// A shelf belongs to the space it was published to rather than to the pubkey that signed it.
- const boards = derived(deriveEventsForUrl(url, [{kinds: [PINBOARD]}]), $events =>
- $events.map(reader(Pinboard)),
+ const boards = derived($events.forUrl(url, [{kinds: [PINBOARD]}]).$, $pinboards =>
+ $pinboards.map(reader(Pinboard)),
)
const address = $derived($page.url.searchParams.get("board") ?? "")
diff --git a/src/routes/spaces/[relay]/polls/[id]/+page.svelte b/src/routes/spaces/[relay]/polls/[id]/+page.svelte
index d89f2a99..85a7d869 100644
--- a/src/routes/spaces/[relay]/polls/[id]/+page.svelte
+++ b/src/routes/spaces/[relay]/polls/[id]/+page.svelte
@@ -2,7 +2,6 @@
import {onDestroy, onMount} from "svelte"
import {sleep} from "@welshman/lib"
import {POLL, POLL_RESPONSE, getCommentFiltersForRoot} from "@welshman/util"
- import {deriveEventsAsc} from "@welshman/store"
import SortVertical from "@assets/icons/sort-vertical.svg?dataurl"
import Icon from "@lib/components/Icon.svelte"
import PageContent from "@lib/components/PageContent.svelte"
@@ -13,8 +12,7 @@
import NoteContent from "@app/components/NoteContent.svelte"
import CommentActions from "@app/components/CommentActions.svelte"
import EventReply from "@app/components/EventReply.svelte"
- import {network} from "@app/core"
- import {deriveEvent, deriveEventsById} from "@app/repository"
+ import {events, network} from "@app/core"
import {makeFeedContext} from "@app/feeds"
import {decodeRelay} from "@app/relays"
import type {PageProps} from "./$types"
@@ -24,9 +22,9 @@
const {relay, id} = params
const url = decodeRelay(relay)
const context = makeFeedContext({relays: [url]})
- const event = deriveEvent(id, [url])
+ const event = $events.one(id, [url]).$
const filters = $derived($event ? getCommentFiltersForRoot([$event]) : [])
- const comments = $derived(deriveEventsAsc(deriveEventsById(filters)))
+ const comments = $derived($events.asc(filters).$)
const back = () => history.back()
diff --git a/src/routes/spaces/[relay]/threads/[id]/+page.svelte b/src/routes/spaces/[relay]/threads/[id]/+page.svelte
index 47954235..53ed27c8 100644
--- a/src/routes/spaces/[relay]/threads/[id]/+page.svelte
+++ b/src/routes/spaces/[relay]/threads/[id]/+page.svelte
@@ -3,7 +3,6 @@
import {page} from "$app/state"
import {sleep, spec} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
- import {deriveEventsAsc} from "@welshman/store"
import {getCommentFiltersForRoot} from "@welshman/util"
import Reply from "@assets/icons/reply-2.svg?dataurl"
import AltArrowDown from "@assets/icons/alt-arrow-down.svg?dataurl"
@@ -15,8 +14,7 @@
import ThreadPost from "@app/components/ThreadPost.svelte"
import ThreadSummaryBar from "@app/components/ThreadSummaryBar.svelte"
import EventReply from "@app/components/EventReply.svelte"
- import {deriveEvent, deriveEventsById} from "@app/repository"
- import {network} from "@app/core"
+ import {events, network} from "@app/core"
import {makeFeedContext} from "@app/feeds"
import {getChecked} from "@app/notifications"
import {decodeRelay} from "@app/relays"
@@ -29,11 +27,11 @@
const {relay, id} = params
const url = decodeRelay(relay)
- const event = deriveEvent(id, [url])
+ const event = $events.one(id, [url]).$
// Rows register themselves with `related`, so the whole page's reactions load in one batch
const context = makeFeedContext({relays: [url]})
const filters = $derived($event ? getCommentFiltersForRoot([$event]) : [])
- const replies = $derived(deriveEventsAsc(deriveEventsById(filters)))
+ const replies = $derived($events.asc(filters).$)
const scrollToTop = () => element?.scrollTo({top: 0, behavior: "smooth"})