style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
+21
-35
@@ -8,9 +8,9 @@
|
||||
* Source: RESEARCH.md § "User upsert with color assignment"
|
||||
*/
|
||||
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
import { db } from '../db/client.js'
|
||||
import { users } from '../db/schema.js'
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { db } from '../db/client.js';
|
||||
import { users } from '../db/schema.js';
|
||||
|
||||
/**
|
||||
* Accessible, visually-distinct palette for per-member member-color assignment.
|
||||
@@ -29,11 +29,11 @@ export const COLOR_PALETTE: string[] = [
|
||||
'#9B6DC5', // soft purple
|
||||
'#E8A840', // warm amber (near shared rose — assigned only after cool colors)
|
||||
'#E8734A', // warm coral (closest to shared rose — assigned last)
|
||||
]
|
||||
];
|
||||
|
||||
/** Coerce an OIDC claim to a trimmed non-empty string, else undefined. */
|
||||
const claimStr = (v: unknown): string | undefined =>
|
||||
typeof v === 'string' && v.trim() !== '' ? v.trim() : undefined
|
||||
typeof v === 'string' && v.trim() !== '' ? v.trim() : undefined;
|
||||
|
||||
/**
|
||||
* Derive the best available display name from OIDC claims, in preference order:
|
||||
@@ -54,16 +54,13 @@ const claimStr = (v: unknown): string | undefined =>
|
||||
* so the write-path upsert agrees with /api/me.
|
||||
*/
|
||||
export function deriveDisplayName(claims: {
|
||||
name?: unknown
|
||||
preferred_username?: unknown
|
||||
email?: unknown
|
||||
name?: unknown;
|
||||
preferred_username?: unknown;
|
||||
email?: unknown;
|
||||
}): string | null {
|
||||
return (
|
||||
claimStr(claims.name) ??
|
||||
claimStr(claims.preferred_username) ??
|
||||
claimStr(claims.email) ??
|
||||
null
|
||||
)
|
||||
claimStr(claims.name) ?? claimStr(claims.preferred_username) ?? claimStr(claims.email) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,17 +73,13 @@ export function deriveDisplayName(claims: {
|
||||
* Never keys on email or displayName for identity. displayName is stored as a
|
||||
* display hint only and may change without affecting identity.
|
||||
*/
|
||||
export async function upsertUser(
|
||||
oidcIss: string,
|
||||
oidcSub: string,
|
||||
displayName?: string | null,
|
||||
) {
|
||||
export async function upsertUser(oidcIss: string, oidcSub: string, displayName?: string | null) {
|
||||
// 1. Look up by composite identity key (iss + sub) — never email
|
||||
const existing = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(and(eq(users.oidcIss, oidcIss), eq(users.oidcSub, oidcSub)))
|
||||
.limit(1)
|
||||
.limit(1);
|
||||
|
||||
if (existing[0]) {
|
||||
// Track the IdP display name authoritatively: when the caller supplies a
|
||||
@@ -97,13 +90,10 @@ export async function upsertUser(
|
||||
// A null displayName (no usable claim this request) never overwrites a good
|
||||
// stored value.
|
||||
if (displayName != null && displayName !== existing[0].displayName) {
|
||||
await db
|
||||
.update(users)
|
||||
.set({ displayName })
|
||||
.where(eq(users.id, existing[0].id))
|
||||
return { ...existing[0], displayName }
|
||||
await db.update(users).set({ displayName }).where(eq(users.id, existing[0].id));
|
||||
return { ...existing[0], displayName };
|
||||
}
|
||||
return existing[0]
|
||||
return existing[0];
|
||||
}
|
||||
|
||||
// 2. Assign the first palette color NOT already in use by another member.
|
||||
@@ -113,11 +103,11 @@ export async function upsertUser(
|
||||
// guarantees distinct, stable colors for up to COLOR_PALETTE.length members
|
||||
// (AUTH-03). Falls back to round-robin by count only once the palette is
|
||||
// exhausted (more members than colors).
|
||||
const usedRows = await db.select({ color: users.color }).from(users)
|
||||
const usedColors = new Set(usedRows.map((r) => r.color))
|
||||
const usedRows = await db.select({ color: users.color }).from(users);
|
||||
const usedColors = new Set(usedRows.map((r) => r.color));
|
||||
const color =
|
||||
COLOR_PALETTE.find((c) => !usedColors.has(c)) ??
|
||||
COLOR_PALETTE[usedColors.size % COLOR_PALETTE.length]
|
||||
COLOR_PALETTE[usedColors.size % COLOR_PALETTE.length];
|
||||
|
||||
// 3. Insert new user row
|
||||
// mysql2 has no RETURNING clause — use $returningId() then re-select
|
||||
@@ -129,14 +119,10 @@ export async function upsertUser(
|
||||
displayName: displayName ?? null,
|
||||
color,
|
||||
})
|
||||
.$returningId()
|
||||
.$returningId();
|
||||
|
||||
// 4. Re-select to return the full typed row
|
||||
const [newUser] = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, inserted.id))
|
||||
.limit(1)
|
||||
const [newUser] = await db.select().from(users).where(eq(users.id, inserted.id)).limit(1);
|
||||
|
||||
return newUser
|
||||
return newUser;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user