feat(spaces): resolve member DIDs to usernames in space settings
Add POST /api/users/resolve-dids batch endpoint in EncryptID, proxy /api/users/* through rspace server, and batch-resolve missing displayNames in the space settings panel so owners and members show usernames not DIDs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a415d6c308
commit
acafe15c4b
|
|
@ -452,7 +452,7 @@ app.all("/encryptid/*", async (c) => {
|
|||
}
|
||||
});
|
||||
|
||||
// ── User API proxy (forward /api/user/* to EncryptID for tab state, prefs) ──
|
||||
// ── User API proxy (forward /api/user/* and /api/users/* to EncryptID) ──
|
||||
app.all("/api/user/*", async (c) => {
|
||||
const targetUrl = `${ENCRYPTID_INTERNAL}${c.req.path}${new URL(c.req.url).search}`;
|
||||
const headers = new Headers(c.req.raw.headers);
|
||||
|
|
@ -470,6 +470,23 @@ app.all("/api/user/*", async (c) => {
|
|||
return c.json({ error: "EncryptID service unavailable" }, 502);
|
||||
}
|
||||
});
|
||||
app.all("/api/users/*", async (c) => {
|
||||
const targetUrl = `${ENCRYPTID_INTERNAL}${c.req.path}${new URL(c.req.url).search}`;
|
||||
const headers = new Headers(c.req.raw.headers);
|
||||
headers.delete("host");
|
||||
try {
|
||||
const res = await fetch(targetUrl, {
|
||||
method: c.req.method,
|
||||
headers,
|
||||
body: c.req.method !== "GET" && c.req.method !== "HEAD" ? c.req.raw.body : undefined,
|
||||
// @ts-ignore duplex needed for streaming request bodies
|
||||
duplex: "half",
|
||||
});
|
||||
return new Response(res.body, { status: res.status, headers: res.headers });
|
||||
} catch (e: any) {
|
||||
return c.json({ error: "EncryptID service unavailable" }, 502);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Existing /api/communities/* routes (backward compatible) ──
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,26 @@ export class RStackSpaceSettings extends HTMLElement {
|
|||
} catch {}
|
||||
}
|
||||
|
||||
// Resolve missing displayNames from EncryptID
|
||||
const unresolvedDids = this._members.filter(m => !m.displayName).map(m => m.did);
|
||||
if (unresolvedDids.length && token) {
|
||||
try {
|
||||
const res = await fetch("/api/users/resolve-dids", {
|
||||
method: "POST",
|
||||
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ dids: unresolvedDids }),
|
||||
});
|
||||
if (res.ok) {
|
||||
const resolved = await res.json() as Record<string, { username: string; displayName: string }>;
|
||||
for (const m of this._members) {
|
||||
if (!m.displayName && resolved[m.did]) {
|
||||
m.displayName = resolved[m.did].displayName || resolved[m.did].username;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Determine my role
|
||||
if (session?.claims?.sub) {
|
||||
this._isOwner = session.claims.sub === this._ownerDID;
|
||||
|
|
|
|||
|
|
@ -3817,6 +3817,26 @@ app.get('/api/users/lookup', async (c) => {
|
|||
});
|
||||
});
|
||||
|
||||
// POST /api/users/resolve-dids — batch-resolve DIDs to usernames
|
||||
app.post('/api/users/resolve-dids', async (c) => {
|
||||
const claims = await verifyTokenFromRequest(c.req.header('Authorization'));
|
||||
if (!claims) return c.json({ error: 'Authentication required' }, 401);
|
||||
|
||||
const body = await c.req.json();
|
||||
const dids: string[] = Array.isArray(body.dids) ? body.dids.slice(0, 100) : [];
|
||||
if (!dids.length) return c.json({});
|
||||
|
||||
// Query all matching users in one go
|
||||
const rows = await sql`SELECT id, did, username, display_name FROM users WHERE did = ANY(${dids}) OR id = ANY(${dids})`;
|
||||
const result: Record<string, { username: string; displayName: string }> = {};
|
||||
for (const row of rows) {
|
||||
const entry = { username: row.username, displayName: row.display_name || row.username };
|
||||
if (row.did) result[row.did] = entry;
|
||||
result[row.id] = entry;
|
||||
}
|
||||
return c.json(result);
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// SPACE INVITE ROUTES
|
||||
// ============================================================================
|
||||
|
|
|
|||
Loading…
Reference in New Issue