@decentnetwork/beagle 0.1.92 → 0.1.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/desktop/app.js +1 -1
- package/dist/server.js +62 -9
- package/package.json +1 -1
package/dist/desktop/app.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -75,6 +75,50 @@ async function ensFetchJson(path) {
|
|
|
75
75
|
clearTimeout(timer);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
/** requestedAt / acceptedAt per friend, read from the SDK's own friend store
|
|
79
|
+
* (`<keyFile>.friends.json`, next to the identity). The daemon's friends-list
|
|
80
|
+
* reports neither for a request we sent and only acceptedAt (as lastSeen)
|
|
81
|
+
* otherwise, so a friend just added had no stamp at all and sorted to the
|
|
82
|
+
* bottom — the third time this was reported. The store is the source of
|
|
83
|
+
* truth both backends write, and it is a file in our own config dir, so
|
|
84
|
+
* read it. Cached by mtime: the list is polled every 2.5s per tab. */
|
|
85
|
+
let friendStampsCache = null;
|
|
86
|
+
function friendStoreStamps(keyFile) {
|
|
87
|
+
const empty = new Map();
|
|
88
|
+
if (!keyFile)
|
|
89
|
+
return empty;
|
|
90
|
+
const path = `${keyFile}.friends.json`;
|
|
91
|
+
try {
|
|
92
|
+
const st = statSync(path);
|
|
93
|
+
if (friendStampsCache && friendStampsCache.mtimeMs === st.mtimeMs)
|
|
94
|
+
return friendStampsCache.map;
|
|
95
|
+
const raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
96
|
+
const recs = Array.isArray(raw)
|
|
97
|
+
? raw
|
|
98
|
+
: raw && typeof raw === "object" && Array.isArray(raw.friends)
|
|
99
|
+
? raw.friends
|
|
100
|
+
: Object.values(raw ?? {});
|
|
101
|
+
const map = new Map();
|
|
102
|
+
for (const r of recs) {
|
|
103
|
+
if (!r || typeof r !== "object")
|
|
104
|
+
continue;
|
|
105
|
+
const id = r.userid || r.pubkey;
|
|
106
|
+
if (!id)
|
|
107
|
+
continue;
|
|
108
|
+
map.set(id, {
|
|
109
|
+
requestedAt: typeof r.requestedAt === "number" ? r.requestedAt : undefined,
|
|
110
|
+
acceptedAt: typeof r.acceptedAt === "number" ? r.acceptedAt : undefined,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
friendStampsCache = { mtimeMs: st.mtimeMs, map };
|
|
114
|
+
return map;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Unreadable or absent (a fresh install has no friends yet): whatever we
|
|
118
|
+
// last read, else nothing — the list still renders, just without stamps.
|
|
119
|
+
return friendStampsCache?.map ?? empty;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
78
122
|
/** The record beagle writes for its own name: what the profile page shows
|
|
79
123
|
* (displayName, description) on top of whatever the record already held —
|
|
80
124
|
* wallet binds, socials, avatar, referee — so a profile edit never strips a
|
|
@@ -1966,10 +2010,13 @@ export function startBeagleServer(opts) {
|
|
|
1966
2010
|
beagleVer: beagleVersion(),
|
|
1967
2011
|
};
|
|
1968
2012
|
const fl = (flist.ok ? (flist.data?.friends ?? []) : []);
|
|
2013
|
+
const stamps = friendStoreStamps(opts.callIce?.keyFile);
|
|
1969
2014
|
const peers = fl.map((f) => {
|
|
1970
2015
|
const uid = f.userid ?? "";
|
|
1971
2016
|
const sess = sessByUserid.get(uid);
|
|
1972
2017
|
const status = f.status;
|
|
2018
|
+
const stamp = stamps.get(uid);
|
|
2019
|
+
const acceptedAt = f.lastSeen ?? stamp?.acceptedAt ?? 0;
|
|
1973
2020
|
const online = status === "connected" || status === "online";
|
|
1974
2021
|
const realName = typeof f.name === "string" && f.name !== uid ? f.name : undefined;
|
|
1975
2022
|
const lm = f.lastMessage;
|
|
@@ -1982,10 +2029,14 @@ export function startBeagleServer(opts) {
|
|
|
1982
2029
|
address: f.address || "",
|
|
1983
2030
|
online,
|
|
1984
2031
|
// Friendship not yet accepted by the other side. Only trusted when
|
|
1985
|
-
// the backend states it explicitly
|
|
1986
|
-
//
|
|
1987
|
-
//
|
|
1988
|
-
|
|
2032
|
+
// the backend states it explicitly: the embedded host's `accepted`,
|
|
2033
|
+
// or — on the daemon — SDK status "requested" WITH no acceptedAt.
|
|
2034
|
+
// Status alone is not enough: the daemon keeps "requested" on a
|
|
2035
|
+
// friend who accepted but has never connected since, and reading
|
|
2036
|
+
// it as pending put the waiting banner on 22 of 65 friends.
|
|
2037
|
+
// Anything else defaults to established, so the banner can never
|
|
2038
|
+
// wrongly appear on an old backend.
|
|
2039
|
+
pending: f.accepted === false || (status === "requested" && !acceptedAt),
|
|
1989
2040
|
via: online ? viaFromTransport(sess?.transport) : null,
|
|
1990
2041
|
ping: null,
|
|
1991
2042
|
ip: ipByUserid.get(uid) ?? "",
|
|
@@ -2005,11 +2056,13 @@ export function startBeagleServer(opts) {
|
|
|
2005
2056
|
// The sidebar ranks a friend by the newest of these and the last
|
|
2006
2057
|
// message, so someone you just accepted — or just added — lands
|
|
2007
2058
|
// at the top like a fresh message would, not in a no-history
|
|
2008
|
-
// group at the bottom.
|
|
2009
|
-
//
|
|
2010
|
-
//
|
|
2011
|
-
|
|
2012
|
-
|
|
2059
|
+
// group at the bottom. The backend's own fields first; the SDK's
|
|
2060
|
+
// friend store on disk fills what the backend does not report — a
|
|
2061
|
+
// daemon backend gives only lastSeen (its acceptedAt) and nothing
|
|
2062
|
+
// for a request we sent, which left a just-added friend with no
|
|
2063
|
+
// stamp at all.
|
|
2064
|
+
acceptedAt,
|
|
2065
|
+
requestedAt: f.requestedAt ?? stamp?.requestedAt ?? 0,
|
|
2013
2066
|
wire: "163",
|
|
2014
2067
|
avatarUrl: ensPub.get(uid)?.avatarUrl ?? null,
|
|
2015
2068
|
// What they advertised over Carrier wins over the directory: it is
|
package/package.json
CHANGED