refactor(auth): keep the account payload handler and chat schemas in size

The createdAt field and the locale import grew files the size ratchet
holds. The account payload's insurance-number decryption moves into
its own helper, the import joins the zod one, and two comments lose a
wrapped line, so no baseline has to rise.
This commit is contained in:
Marc-André Bombeck committed 2026-10-29 09:42:31 +01:00
1 parent d7409b38d7
commit f92889ab88
4 files changed
+25 -29

No files matched your search

+18 -14
View File
@@ -93,6 +93,21 @@ const SERVER_FEATURES = {
lifeCircumstances: true,
} as const;
/**
* v1.7.0 — patient-identity fields for the health-record export. The KVNR is
* stored encrypted; decrypt fail-soft so a key-rotation gap on one row never
* 500s the whole profile fetch (the field just reads null and the user
* re-enters it).
*/
function readInsuranceNumber(encrypted: string | null | undefined) {
if (!encrypted) return null;
try {
return decrypt(encrypted);
} catch {
return null;
}
}
export const GET = apiHandler(async () => {
const auth = await requireActorAuth();
const { user } = auth;
@@ -289,24 +304,13 @@ export const GET = apiHandler(async () => {
sectionsOpen(sections, "cycle") &&
isCycleEnabled(record?.gender ?? null, cycleProfile);
// v1.7.0 — patient-identity fields for the health-record export. The
// KVNR is stored encrypted; decrypt fail-soft so a key-rotation gap on
// one row never 500s the whole profile fetch (the field just reads
// null and the user re-enters it).
let insuranceNumber: string | null = null;
if (identity?.insuranceNumberEncrypted) {
try {
insuranceNumber = decrypt(identity.insuranceNumberEncrypted);
} catch {
insuranceNumber = null;
}
}
const insuranceNumber = readInsuranceNumber(
identity?.insuranceNumberEncrypted,
);
return apiSuccess({
id: user.id,
username: user.username,
// When the caller's account was created. The dashboard greeting says
// "welcome", not "welcome back", during an account's first day.
createdAt: user.createdAt,
email: user.email,
role: user.role ?? "USER",
@@ -1,6 +1,5 @@
"use client";
import type { Locale } from "@/lib/i18n/config";
import {
useCallback,
useEffect,
@@ -896,7 +895,7 @@ export interface SendCoachMessageParams {
conversationId?: string;
message: string;
prefill?: string;
locale?: Locale;
locale?: import("@/lib/i18n/config").Locale;
/**
* v1.4.20.1 — optional snapshot scope (per-source toggles + window)
* driven by the sources-rail picker. When omitted the server falls
+5 -11
View File
@@ -7,7 +7,6 @@
* can pass messages through with minimal translation.
*/
import { z } from "zod/v4";
import { locales } from "@/lib/i18n/config";
import { COACH_SCOPE_SOURCES } from "./scope-sources";
@@ -87,19 +86,14 @@ export const coachChatRequestSchema = z.object({
conversationId: z.string().min(1).max(64).optional(),
message: z.string().min(1).max(4000),
prefill: z.string().max(2000).optional(),
/**
* The reply language: any UI locale. Overrides the cookie and the account's
* stored language for this turn (`resolveServerLocale`).
*/
locale: z.enum(locales).optional(),
scope: coachScopeSchema.optional(),
/**
* v1.16.6 — guided clarifying-questions flow: the pending question
* this message answers. The question bubble is client-side only
* (never persisted), so without this context the model would see a
* bare answer ("since 2019, with medication") and could not react
* to it. Rides the prompt as delimited user-provided context; the
* persisted user turn stays the answer alone.
* v1.16.6 — guided clarifying-questions flow: the pending question this
* message answers. The question bubble is client-side only (never persisted),
* so without this context the model would see a bare answer ("since 2019,
* with medication") and could not react to it. Rides the prompt as delimited
* user-provided context; the persisted user turn stays the answer alone.
*/
guidedQuestion: z.string().min(1).max(500).optional(),
/**
+1 -2
View File
@@ -945,8 +945,7 @@ export const DOCUMENT_CHAT_MESSAGE_MAX = 4000;
* Request body for `POST /api/documents/inbound/{id}/chat`. No `userId` and no
* `documentId` field — the user is narrowed from the session and the document id
* comes from the path. `conversationId` continues an existing thread scoped to
* this document; omitting it starts a new one. `locale` is the reply language,
* any UI locale, like the Coach's.
* this document; omitting it starts a new one. `locale` is the reply language.
*/
export const documentChatRequestSchema = z
.object({