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:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
+9 -9
View File
@@ -24,8 +24,8 @@
* - This file must never be removed — the pattern is referenced by Plan 02 routes.
*/
import type { MiddlewareHandler } from 'hono'
import { COLOR_PALETTE } from './user.js'
import type { MiddlewareHandler } from 'hono';
import { COLOR_PALETTE } from './user.js';
export const DEV_USER = {
id: 1,
@@ -33,7 +33,7 @@ export const DEV_USER = {
oidcSub: 'dev-user',
displayName: 'Dev User',
color: COLOR_PALETTE[0], // '#4A90D9' — first palette slot
} as const
} as const;
/**
* Extend Hono's ContextVariableMap so that c.get('user') / c.set('user', ...)
@@ -43,7 +43,7 @@ export const DEV_USER = {
*/
declare module 'hono' {
interface ContextVariableMap {
user: typeof DEV_USER
user: typeof DEV_USER;
}
}
@@ -59,18 +59,18 @@ export function devAuthBypass(): MiddlewareHandler {
// Hard production guard — FIRST check, before reading any other env var.
// Ensures this middleware can never grant access in production regardless of config.
if (process.env.NODE_ENV === 'production') {
return async (_c, next) => next()
return async (_c, next) => next();
}
// Bypass flag not set — passthrough; OIDC auth proceeds normally.
if (process.env.DEV_AUTH_BYPASS !== 'true') {
return async (_c, next) => next()
return async (_c, next) => next();
}
// Bypass active: inject fixed dev user into Hono context.
// Routes that read c.get('user') will receive DEV_USER.
return async (c, next) => {
c.set('user', DEV_USER)
await next()
}
c.set('user', DEV_USER);
await next();
};
}
+1 -1
View File
@@ -23,4 +23,4 @@
* Source: https://github.com/honojs/middleware/tree/main/packages/oidc-auth
*/
export { oidcAuthMiddleware, processOAuthCallback, getAuth } from '@hono/oidc-auth'
export { oidcAuthMiddleware, processOAuthCallback, getAuth } from '@hono/oidc-auth';
+13 -13
View File
@@ -21,8 +21,8 @@
* cookie only when the library produced a valid session this request.
*/
import type { MiddlewareHandler } from 'hono'
import { setCookie } from 'hono/cookie'
import type { MiddlewareHandler } from 'hono';
import { setCookie } from 'hono/cookie';
/**
* Returns a Hono MiddlewareHandler that upgrades the session-scoped oidc-auth cookie
@@ -37,7 +37,7 @@ export function persistSessionCookie(): MiddlewareHandler {
// The 'as never' cast is required because 'oidcAuthJwt' is a library-internal key
// that is not declared in Hono's ContextVariableMap — mirrors the loose-context
// convention used elsewhere in this codebase (e.g. resolveUserId).
const jwt = c.get('oidcAuthJwt' as never) as string | undefined
const jwt = c.get('oidcAuthJwt' as never) as string | undefined;
// CRITICAL CORRECTNESS GUARD: if no valid session JWT is on context (logged-out,
// deleted, or never-set request), do NOT touch cookies and fall straight through.
@@ -45,16 +45,16 @@ export function persistSessionCookie(): MiddlewareHandler {
// logged-out user would receive a new oidc-auth Set-Cookie with no value, which
// could re-authenticate them or produce confusing browser state.
if (!jwt) {
await next()
return
await next();
return;
}
// A valid session JWT is present — re-issue the cookie BEFORE next() so that if
// any future downstream handler deletes the cookie, that delete Set-Cookie header
// comes last and wins (safe ordering even without a current logout/revoke route).
const name = process.env.OIDC_COOKIE_NAME ?? 'oidc-auth'
const path = process.env.OIDC_COOKIE_PATH ?? '/'
const maxAge = Number(process.env.OIDC_AUTH_EXPIRES ?? 86400)
const name = process.env.OIDC_COOKIE_NAME ?? 'oidc-auth';
const path = process.env.OIDC_COOKIE_PATH ?? '/';
const maxAge = Number(process.env.OIDC_AUTH_EXPIRES ?? 86400);
// Build the options object. domain is included ONLY when OIDC_COOKIE_DOMAIN is set —
// mirroring the library's own conditional-domain logic so the two Set-Cookie headers
@@ -66,15 +66,15 @@ export function persistSessionCookie(): MiddlewareHandler {
secure: true,
sameSite: 'Lax',
maxAge, // seconds — Hono's setCookie maxAge unit matches OIDC_AUTH_EXPIRES unit
}
};
if (process.env.OIDC_COOKIE_DOMAIN) {
options.domain = process.env.OIDC_COOKIE_DOMAIN
options.domain = process.env.OIDC_COOKIE_DOMAIN;
}
// Re-issue the same JWT the library signed. Do NOT re-sign or modify the payload.
setCookie(c, name, jwt, options)
setCookie(c, name, jwt, options);
await next()
}
await next();
};
}
+21 -35
View File
@@ -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;
}