Website header: the T5DE logo, four links, and a profile menu
CI / test (push) Successful in 1m11s

The header shows T5DE's logo (the client's, also the tab icon) and Online, Rooms, Products and
Catalogs; the person's pages (Account, Library, Console for moderators) and signing out are in a menu
under their picture: their first linked IMVU account's avatar picture, which /me now gives (kept an
hour), or their initial. Creating a product moves to Products (New product, /products/new; /create
redirects there), as creating a room is on Rooms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-30 07:18:26 -07:00
1 parent 76c8e0342e
commit 07bbc11565
19 files changed
+160 -79

No files matched your search

+26 -1
View File
@@ -4,6 +4,7 @@
import { Elysia, t } from "elysia";
import {
and,
asc,
desc,
eq,
ilike,
@@ -151,6 +152,30 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
banReason: p.banReason ?? "",
});
/** A person's picture, for the website's header: their first linked IMVU account's avatar picture (null if none,
* or IMVU can't say). Kept an hour per account, so pages don't each ask IMVU. */
const pictures = new Map<number, { url: string | null; at: number }>();
const picture = async (userId: string): Promise<string | null> => {
const [first] = await db
.select({ imvuId: imvuLink.imvuId })
.from(imvuLink)
.where(eq(imvuLink.userId, userId))
.orderBy(asc(imvuLink.linkedAt))
.limit(1);
if (!first) return null;
const kept = pictures.get(first.imvuId);
if (kept && Date.now() - kept.at < 60 * 60 * 1000) return kept.url;
let url: string | null = kept?.url ?? null;
try {
url = (await imvu.byId(first.imvuId)).picture;
} catch {
// IMVU unavailable: the last known one (or none), asked again next time.
return url;
}
pictures.set(first.imvuId, { url, at: Date.now() });
return url;
};
/** Links as the website shows them: with live presence, and age by the one rule. */
const linkViews = async (userId: string, links: Link[]) => {
const ids = links.map((l) => l.imvuId);
@@ -442,7 +467,7 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
})
// Who's signed in, and the home page.
.get("/me", ({ me }) => ({ person: personView(me) }), { signedIn: true })
.get("/me", async ({ me }) => ({ person: { ...personView(me), picture: await picture(me.id) } }), { signedIn: true })
.get("/home", async ({ person }) => {
const online = (await visibleOnline(person)).length;
if (!person) return { onlineCount: online };
+2
View File
@@ -8,6 +8,7 @@ export type ImvuUser = {
tagline: string;
ageVerified: boolean;
accessPass: boolean;
picture: string | null; // the avatar's picture (https, on *.imvu.com)
};
export type ImvuRoom = {
@@ -182,5 +183,6 @@ export function parse(answer: unknown): ImvuUser {
tagline: typeof data.tagline === "string" ? data.tagline : "",
ageVerified: data.is_ageverified === true,
accessPass: data.is_ap === true,
picture: imvuImage(data.thumbnail_url),
};
}