fix: date repositories from their state #23
@@ -184,6 +184,11 @@ pub fn all_announcements() -> Filter {
|
||||
Filter::new().kind(Kind::GitRepoAnnouncement)
|
||||
}
|
||||
|
||||
/// All repository state events, carrying each repository's refs and last push time.
|
||||
pub fn all_states() -> Filter {
|
||||
Filter::new().kind(Kind::RepoState)
|
||||
}
|
||||
|
||||
/// How far back deletion requests are fetched and stored.
|
||||
const DELETIONS_LOOKBACK: Duration = Duration::from_secs(3 * 365 * 86_400);
|
||||
|
||||
|
||||
@@ -207,7 +207,11 @@ impl RepoStore {
|
||||
update.kind == Kind::EventDeletion || update.kind == Kind::RequestToVanish;
|
||||
let coordinate = update.coordinate.as_ref() == Some(addr);
|
||||
let author = update.author == addr.public_key;
|
||||
let kind = update.kind == Kind::GitRepoAnnouncement;
|
||||
// Announcements and state share the owner and identifier.
|
||||
// State events carry `d`, not `a`, so `coordinate` misses them.
|
||||
let authored = (update.kind == Kind::GitRepoAnnouncement
|
||||
|| update.kind == Kind::RepoState)
|
||||
&& author;
|
||||
// NIP-22 comments carry no `a` tag.
|
||||
// Coordinate matching fails for them.
|
||||
// Any comment may reference this repository's roots.
|
||||
@@ -216,18 +220,22 @@ impl RepoStore {
|
||||
// Any status event may reference a root of this repository.
|
||||
let status = RepoStatus::from_kind(update.kind).is_some();
|
||||
|
||||
deletion || coordinate || (author && kind) || comment || status
|
||||
deletion || coordinate || authored || comment || status
|
||||
}),
|
||||
BackendEvent::Published(event) => {
|
||||
let kind = event.kind == Kind::GitRepoAnnouncement;
|
||||
let announcement = event.kind == Kind::GitRepoAnnouncement;
|
||||
let author = event.pubkey == addr.public_key;
|
||||
let coordinate = event.tags.coordinates().into_iter().any(|c| c == *addr);
|
||||
// State events carry their repository id in the `d` tag.
|
||||
let state = event.kind == Kind::RepoState
|
||||
&& author
|
||||
&& event.tags.identifier().as_deref() == Some(addr.identifier.as_str());
|
||||
// Locally published deletions may target any event of this repository.
|
||||
// Refresh so they take effect immediately, like relay deletions.
|
||||
let deletion =
|
||||
event.kind == Kind::EventDeletion || event.kind == Kind::RequestToVanish;
|
||||
|
||||
coordinate || (kind && author) || deletion
|
||||
coordinate || (announcement && author) || state || deletion
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@@ -83,12 +83,16 @@ impl RepoListStore {
|
||||
BackendEvent::Published(event) => {
|
||||
let announcement = event.kind == Kind::GitRepoAnnouncement;
|
||||
|
||||
// Locally published state events advance last activity.
|
||||
// Refresh so a push made in this session dates the card immediately.
|
||||
let state = event.kind == Kind::RepoState;
|
||||
|
||||
// Locally published deletions are already in the local database.
|
||||
// Refresh so they take effect immediately, like relay deletions.
|
||||
let deletion =
|
||||
event.kind == Kind::EventDeletion || event.kind == Kind::RequestToVanish;
|
||||
|
||||
announcement || deletion
|
||||
announcement || state || deletion
|
||||
}
|
||||
// Only a completed sync refreshes the list.
|
||||
// Progress ticks would re-scan the whole database several times
|
||||
@@ -133,6 +137,9 @@ impl RepoListStore {
|
||||
|
||||
backend.update(cx, |backend, cx| {
|
||||
backend.sync_bootstrap(filters::all_announcements(), cx);
|
||||
// State events carry the last push time, so syncing them globally
|
||||
// lets the list date every repository without the user opening it.
|
||||
backend.sync_bootstrap(filters::all_states(), cx);
|
||||
// Deletion requests, NIP-09/62, must be known before any announcement is shown.
|
||||
backend.sync_bootstrap(filters::deletions(), cx);
|
||||
});
|
||||
|
||||
@@ -123,24 +123,26 @@ flowchart TD
|
||||
|
||||
## Remediation options
|
||||
|
||||
- **A. Global state sync (smallest change).**
|
||||
Add `sync_bootstrap(Filter::new().kind(Kind::RepoState))` alongside the announcement
|
||||
sync in `RepoListStore::subscribe_remote`. Kind `30618` is addressable, so relays
|
||||
keep one event per repository — volume comparable to announcements. Caveat: coverage
|
||||
depends on whether state events reach the bootstrap relays; if a grasp server is the
|
||||
only holder, those repositories remain unseen.
|
||||
- **A. Global state sync (smallest change). — implemented.**
|
||||
`RepoListStore::subscribe_remote` now also syncs `filters::all_states()`
|
||||
(`Filter::new().kind(Kind::RepoState)`) alongside the announcement sync. Kind `30618`
|
||||
is addressable, so relays keep one event per repository — volume comparable to
|
||||
announcements. Caveat: coverage depends on whether state events reach the bootstrap
|
||||
relays; if a grasp server is the only holder, those repositories remain unseen.
|
||||
|
||||
- **B. Targeted fetch for the user's own repositories.**
|
||||
- **B. Targeted fetch for the user's own repositories. — not implemented.**
|
||||
In `sync_inbox` (`crates/signed_state/src/backend.rs` L1126-1152), where the user's
|
||||
own repositories' relays are already connected, also sync `filters::state(addr)` per
|
||||
own repository. This directly addresses "my repositories updated elsewhere" at low
|
||||
cost. Note the existing race: `sync_inbox` reads the announcement list right after
|
||||
login, which may not be loaded yet.
|
||||
|
||||
- **C. Reactivity fixes.**
|
||||
Include `Kind::RepoState` in the `Published` refresh conditions, and in
|
||||
`RepoStore::subscribe_backend` either match kind plus author, or extend `Update` to
|
||||
carry the `d`-tag identifier.
|
||||
- **C. Reactivity fixes. — implemented.**
|
||||
`Kind::RepoState` is now included in the `BackendEvent::Published` refresh condition of
|
||||
both `RepoListStore` and `RepoStore`. `RepoStore::subscribe_backend` also matches relay
|
||||
state updates by owner plus kind — state events carry `d`, not `a`, so coordinate
|
||||
matching misses them — and locally published state updates by owner plus the `d`
|
||||
identifier.
|
||||
|
||||
Suggested combination: A + C, plus B if own-repository freshness on fresh profiles
|
||||
A + C are implemented; B remains available if own-repository freshness on fresh profiles
|
||||
matters.
|
||||
|
||||
Reference in New Issue
Block a user