openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
44 lines (43 loc) • 1.93 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
//#region src/shared/presence-user.ts
function firstSorted(values) {
return [...values].map(normalizeOptionalString).filter((value) => value !== void 0).toSorted()[0];
}
function presenceEntrySortKey(entry) {
return [
normalizeOptionalString(entry.host) ?? "",
normalizeOptionalString(entry.platform) ?? "",
normalizeOptionalString(entry.deviceFamily) ?? "",
normalizeOptionalString(entry.instanceId) ?? "",
String(entry.ts ?? 0).padStart(16, "0")
].join("\0");
}
function compareText(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
/** Presence namespaces come from recorded identity, never display metadata or raw-id shape. */
function presenceUserKey(user) {
return user.identity ? `profile:${user.identity.id}` : `raw:${user.id}`;
}
/** Online people use the identity namespace established by authentication. */
function groupPresenceUsers(entries) {
const grouped = /* @__PURE__ */ new Map();
for (const entry of entries) {
if (entry.reason === "disconnect" || !entry.user?.id) continue;
const key = presenceUserKey(entry.user);
const existing = grouped.get(key);
if (existing) existing.push(entry);
else grouped.set(key, [entry]);
}
return { users: [...grouped.entries()].toSorted(([a], [b]) => compareText(a, b)).map(([, userEntries]) => ({
id: userEntries[0].user.id,
identity: userEntries[0].user.identity,
name: firstSorted(userEntries.map((entry) => entry.user?.name)),
email: firstSorted(userEntries.map((entry) => entry.user?.email)),
avatarUrl: firstSorted(userEntries.map((entry) => entry.user?.avatarUrl)),
watchedSessions: [...new Set(userEntries.flatMap((entry) => entry.watchedSessions ?? []))].toSorted(),
entries: userEntries.toSorted((a, b) => compareText(presenceEntrySortKey(a), presenceEntrySortKey(b)))
})) };
}
//#endregion
export { presenceUserKey as n, groupPresenceUsers as t };