community: friends, two signed answers on one request carried over soulseek, one answer is only ever pending

This commit is contained in:
KeelrLeek committed 2026-09-02 14:40:33 -05:00
1 parent 6ed6f5b8f8
commit 984738135a
9 files changed
+967 -4

No files matched your search

+30 -1
View File
@@ -63,6 +63,8 @@ export const community = $state({
links: null,
/** username → the last failed ask's reason. */
linkErrors: {},
/** friends_list: every relationship this device holds, newest first. */
friends: [],
/** persona key → ProfileView | {none} | {error} | {pending}: other
* people's signed profiles, read once per session when surfaced. */
remoteProfiles: {},
@@ -306,11 +308,12 @@ export async function initCommunity() {
if (adapterConnected(status)) void refreshPersona();
else if (community.persona) community.persona.available = false;
});
api.onEvent("community:friends", () => void refreshFriends());
api.onEvent("soulseek:user-state", (p) => {
if (p.status === 1 || p.status === 2) noteSeen(p.username);
});
}
await Promise.all([refreshFreenet(), loadContacts(), refreshLinks()]);
await Promise.all([refreshFreenet(), loadContacts(), refreshLinks(), refreshFriends()]);
await refreshPersona();
}
@@ -391,6 +394,32 @@ export async function loadRemoteProfile(key, force = false) {
}
// ---- friends ------------------------------------------------------------------------
export async function refreshFriends() {
try {
community.friends = await api.friendsList();
} catch {
// stays as it was
}
}
const friendAction = (key, fn) => run(key, async () => { await fn(); await refreshFriends(); });
export const friendRequest = (username) => friendAction("friend:" + username, () => api.friendRequest(username));
export const friendAccept = (id) => friendAction("friend:" + id, () => api.friendAccept(id));
export const friendDecline = (id) => friendAction("friend:" + id, () => api.friendDecline(id));
export const friendRemove = (id) => friendAction("friend:" + id, () => api.friendRemove(id));
export const friendForget = (id) => friendAction("friend:" + id, () => api.friendForget(id));
/** The live relationship with a username, if any: friends first, then the
* most recently touched one. */
export const friendshipFor = (username) => {
const n = (username ?? "").trim().toLowerCase();
const mine = community.friends.filter((f) => f.username_normalized === n);
return mine.find((f) => f.state === "friends") ?? mine[0] ?? null;
};
export const friendCount = () => community.friends.filter((f) => f.state === "friends").length;
export const pendingIn = () => community.friends.filter((f) => f.state === "pending-in");
// Dev handle beside `__soulstream` (state.svelte.js): probes reach the store
// through this, never through a bare import (which would be a second copy).
if (import.meta.env.DEV) globalThis.__community = community;
if (import.meta.env.DEV) globalThis.__communityActions = { friendRequest, friendAccept, friendDecline, friendRemove, friendForget, checkLink, refreshFriends };