mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
style: apply prettier across the tree
One-shot prettier pass so the new format:check gate starts from a clean baseline. Formatting only — no behaviour change. Generator-owned and vendored artifacts stay untouched via .prettierignore.
This commit is contained in:
1 parent
b3fea2ef59
commit
1f4ba5939d
1000 files changed
+12130
-8385
No files matched your search
@@ -111,13 +111,17 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
|
||||
// trailing (to == now) episode-window read; the bounded baseline read
|
||||
// goes through measurement.findMany (to != now). ──
|
||||
const dayCoverage = onlyRhr(
|
||||
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), t === "RESTING_HEART_RATE"])),
|
||||
new Map<string, boolean>(
|
||||
ILLNESS_SCAN_TYPES.map((t) => [String(t), t === "RESTING_HEART_RATE"]),
|
||||
),
|
||||
);
|
||||
rollup.probeRollupCoverage.mockResolvedValue(dayCoverage);
|
||||
rollup.readBestGranularityRollups.mockImplementation(
|
||||
async (_u: string, type: string, windowDays: number) => {
|
||||
if (type !== "RESTING_HEART_RATE") return null;
|
||||
const since = new Date(NOW.getTime() - windowDays * 24 * 60 * 60 * 1000);
|
||||
const since = new Date(
|
||||
NOW.getTime() - windowDays * 24 * 60 * 60 * 1000,
|
||||
);
|
||||
const sinceKey = since.toISOString().slice(0, 10);
|
||||
const rows = DAILY.filter((d) => d.day >= sinceKey).map((d) => ({
|
||||
bucketStart: new Date(`${d.day}T00:00:00Z`),
|
||||
@@ -133,10 +137,16 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
|
||||
return rows.length > 0 ? { granularity: "DAY" as const, rows } : null;
|
||||
},
|
||||
);
|
||||
db.measurement.findMany.mockImplementation(async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt: Date } } }) => {
|
||||
if (where.type !== "RESTING_HEART_RATE") return [];
|
||||
return rawRowsWithin(where.measuredAt.gte, where.measuredAt.lt);
|
||||
});
|
||||
db.measurement.findMany.mockImplementation(
|
||||
async ({
|
||||
where,
|
||||
}: {
|
||||
where: { type: string; measuredAt: { gte: Date; lt: Date } };
|
||||
}) => {
|
||||
if (where.type !== "RESTING_HEART_RATE") return [];
|
||||
return rawRowsWithin(where.measuredAt.gte, where.measuredAt.lt);
|
||||
},
|
||||
);
|
||||
|
||||
const dayOut = await computeEpisodeCorrelation("u1", EPISODE, "UTC", NOW);
|
||||
|
||||
@@ -151,7 +161,11 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
|
||||
rollup.probeRollupCoverage.mockResolvedValue(noCoverage);
|
||||
rollup.readBestGranularityRollups.mockResolvedValue(null);
|
||||
db.measurement.findMany.mockImplementation(
|
||||
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
|
||||
async ({
|
||||
where,
|
||||
}: {
|
||||
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
|
||||
}) => {
|
||||
if (where.type !== "RESTING_HEART_RATE") return [];
|
||||
const from = where.measuredAt.gte;
|
||||
const to = where.measuredAt.lt ?? NOW;
|
||||
@@ -192,7 +206,9 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
|
||||
// The vital series must key by the user's day so it lines up with the
|
||||
// tz-keyed onset/feltBetter markers (the off-by-one this fix closes).
|
||||
rollup.probeRollupCoverage.mockResolvedValue(
|
||||
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), false])),
|
||||
new Map<string, boolean>(
|
||||
ILLNESS_SCAN_TYPES.map((t) => [String(t), false]),
|
||||
),
|
||||
);
|
||||
rollup.readBestGranularityRollups.mockResolvedValue(null);
|
||||
|
||||
@@ -203,7 +219,10 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
|
||||
let cursor = Date.parse("2025-12-20T20:00:00Z");
|
||||
const jit = [-2, -1, 0, 1, 2];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
rows.push({ value: 55 + jit[i % jit.length], measuredAt: new Date(cursor) });
|
||||
rows.push({
|
||||
value: 55 + jit[i % jit.length],
|
||||
measuredAt: new Date(cursor),
|
||||
});
|
||||
cursor += 24 * 60 * 60 * 1000;
|
||||
}
|
||||
// Episode-span readings, including the boundary-crossing 03:00Z spike.
|
||||
@@ -215,7 +234,11 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
|
||||
rows.push({ value: 58, measuredAt: new Date("2026-01-17T20:00:00Z") });
|
||||
|
||||
db.measurement.findMany.mockImplementation(
|
||||
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
|
||||
async ({
|
||||
where,
|
||||
}: {
|
||||
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
|
||||
}) => {
|
||||
if (where.type !== "RESTING_HEART_RATE") return [];
|
||||
const from = where.measuredAt.gte.getTime();
|
||||
const to = where.measuredAt.lt?.getTime() ?? NOW.getTime();
|
||||
@@ -249,12 +272,18 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
|
||||
describe("computeEpisodeCorrelation — contamination-guard read window", () => {
|
||||
it("never queries baseline rows on or after the pre-onset lookback start", async () => {
|
||||
rollup.probeRollupCoverage.mockResolvedValue(
|
||||
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), false])),
|
||||
new Map<string, boolean>(
|
||||
ILLNESS_SCAN_TYPES.map((t) => [String(t), false]),
|
||||
),
|
||||
);
|
||||
rollup.readBestGranularityRollups.mockResolvedValue(null);
|
||||
const seen: Array<{ gte: Date; lt?: Date }> = [];
|
||||
db.measurement.findMany.mockImplementation(
|
||||
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
|
||||
async ({
|
||||
where,
|
||||
}: {
|
||||
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
|
||||
}) => {
|
||||
if (where.type === "RESTING_HEART_RATE") seen.push(where.measuredAt);
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -24,11 +24,18 @@ import {
|
||||
const NOW = new Date("2026-02-01T00:00:00Z");
|
||||
|
||||
/** Build a flat baseline series of `days` days at `value`, ending `endDay`. */
|
||||
function flatBaseline(value: number, days: number, endDay: string): VitalDayPoint[] {
|
||||
function flatBaseline(
|
||||
value: number,
|
||||
days: number,
|
||||
endDay: string,
|
||||
): VitalDayPoint[] {
|
||||
const out: VitalDayPoint[] = [];
|
||||
let cursor = Date.parse(`${endDay}T00:00:00Z`);
|
||||
for (let i = 0; i < days; i++) {
|
||||
out.unshift({ day: new Date(cursor).toISOString().slice(0, 10), mean: value });
|
||||
out.unshift({
|
||||
day: new Date(cursor).toISOString().slice(0, 10),
|
||||
mean: value,
|
||||
});
|
||||
cursor -= 24 * 60 * 60 * 1000;
|
||||
}
|
||||
return out;
|
||||
@@ -39,16 +46,30 @@ function flatBaseline(value: number, days: number, endDay: string): VitalDayPoin
|
||||
* is non-zero and stable. Means cycle through `center − jitter … center +
|
||||
* jitter` so the median is `center` and the MAD is ~`jitter/2`.
|
||||
*/
|
||||
function jitteredBaseline(center: number, jitter: number, days: number, endDay: string): VitalDayPoint[] {
|
||||
function jitteredBaseline(
|
||||
center: number,
|
||||
jitter: number,
|
||||
days: number,
|
||||
endDay: string,
|
||||
): VitalDayPoint[] {
|
||||
const base = flatBaseline(center, days, endDay);
|
||||
const offsets = [-jitter, -jitter / 2, 0, jitter / 2, jitter];
|
||||
return base.map((p, i) => ({ ...p, mean: center + offsets[i % offsets.length] }));
|
||||
return base.map((p, i) => ({
|
||||
...p,
|
||||
mean: center + offsets[i % offsets.length],
|
||||
}));
|
||||
}
|
||||
|
||||
function input(over: Partial<IllnessCorrelationInput>): IllnessCorrelationInput {
|
||||
function input(
|
||||
over: Partial<IllnessCorrelationInput>,
|
||||
): IllnessCorrelationInput {
|
||||
return {
|
||||
episodeId: "ep1",
|
||||
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-17", lifecycle: "ACUTE" },
|
||||
window: {
|
||||
onsetDay: "2026-01-10",
|
||||
feltBetterDay: "2026-01-17",
|
||||
lifecycle: "ACUTE",
|
||||
},
|
||||
series: [],
|
||||
source: "DAY",
|
||||
now: NOW,
|
||||
@@ -60,7 +81,8 @@ describe("computeIllnessCorrelation — coverage gate", () => {
|
||||
it("returns insufficient with no baselined vitals", () => {
|
||||
const out = computeIllnessCorrelation(input({ series: [] }));
|
||||
expect(out.status).toBe("insufficient");
|
||||
if (out.status === "insufficient") expect(out.reason).toBe("no_baselined_vitals");
|
||||
if (out.status === "insufficient")
|
||||
expect(out.reason).toBe("no_baselined_vitals");
|
||||
});
|
||||
|
||||
it("returns insufficient when a vital lacks the min baseline days", () => {
|
||||
@@ -164,7 +186,11 @@ describe("computeIllnessCorrelation — golden recovery-gap", () => {
|
||||
];
|
||||
const out = computeIllnessCorrelation(
|
||||
input({
|
||||
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-15", lifecycle: "CHRONIC_ONGOING" },
|
||||
window: {
|
||||
onsetDay: "2026-01-10",
|
||||
feltBetterDay: "2026-01-15",
|
||||
lifecycle: "CHRONIC_ONGOING",
|
||||
},
|
||||
series: [{ type, baselineDays, episodeDays }],
|
||||
}),
|
||||
);
|
||||
@@ -185,7 +211,11 @@ describe("computeIllnessCorrelation — golden recovery-gap", () => {
|
||||
];
|
||||
const out = computeIllnessCorrelation(
|
||||
input({
|
||||
window: { onsetDay: "2026-01-10", feltBetterDay: null, lifecycle: "ACUTE" },
|
||||
window: {
|
||||
onsetDay: "2026-01-10",
|
||||
feltBetterDay: null,
|
||||
lifecycle: "ACUTE",
|
||||
},
|
||||
series: [{ type, baselineDays, episodeDays }],
|
||||
}),
|
||||
);
|
||||
@@ -354,7 +384,9 @@ describe("computeIllnessCorrelation — red-flag escalation", () => {
|
||||
);
|
||||
expect(out.status).toBe("ok");
|
||||
if (out.status !== "ok") return;
|
||||
const fever = out.value.redFlags.find((f) => f.reason === "sustained_fever");
|
||||
const fever = out.value.redFlags.find(
|
||||
(f) => f.reason === "sustained_fever",
|
||||
);
|
||||
expect(fever).toBeDefined();
|
||||
expect(fever?.days).toBe(3);
|
||||
expect(fever?.worstValue).toBe(39.2);
|
||||
@@ -391,7 +423,9 @@ describe("computeIllnessCorrelation — red-flag escalation", () => {
|
||||
);
|
||||
expect(out.status).toBe("ok");
|
||||
if (out.status !== "ok") return;
|
||||
const fever = out.value.redFlags.find((f) => f.reason === "sustained_fever");
|
||||
const fever = out.value.redFlags.find(
|
||||
(f) => f.reason === "sustained_fever",
|
||||
);
|
||||
expect(fever).toBeDefined();
|
||||
expect(fever?.days).toBe(3);
|
||||
});
|
||||
@@ -418,7 +452,11 @@ describe("computeIllnessCorrelation — return anchor", () => {
|
||||
];
|
||||
const out = computeIllnessCorrelation(
|
||||
input({
|
||||
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-15", lifecycle: "ACUTE" },
|
||||
window: {
|
||||
onsetDay: "2026-01-10",
|
||||
feltBetterDay: "2026-01-15",
|
||||
lifecycle: "ACUTE",
|
||||
},
|
||||
series: [{ type, baselineDays, episodeDays }],
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -114,7 +114,12 @@ describe("upsertIllnessDayLog", () => {
|
||||
|
||||
it("reports inserted (existed=false) on a fresh row", async () => {
|
||||
db.illnessDayLog.findUnique.mockResolvedValue(null);
|
||||
const result = await upsertIllnessDayLog("u1", "ep1", base, "Europe/Berlin");
|
||||
const result = await upsertIllnessDayLog(
|
||||
"u1",
|
||||
"ep1",
|
||||
base,
|
||||
"Europe/Berlin",
|
||||
);
|
||||
expect(result.existed).toBe(false);
|
||||
const args = db.illnessDayLog.upsert.mock.calls[0][0];
|
||||
expect(args.where).toEqual({
|
||||
@@ -143,7 +148,12 @@ describe("upsertIllnessDayLog", () => {
|
||||
noteEncrypted: null,
|
||||
});
|
||||
// Only fever supplied — functionalImpact must keep the stored 3.
|
||||
await upsertIllnessDayLog("u1", "ep1", { date: "2026-06-16", feverC: 37 }, null);
|
||||
await upsertIllnessDayLog(
|
||||
"u1",
|
||||
"ep1",
|
||||
{ date: "2026-06-16", feverC: 37 },
|
||||
null,
|
||||
);
|
||||
const args = db.illnessDayLog.upsert.mock.calls[0][0];
|
||||
expect(args.update.functionalImpact).toBe(3);
|
||||
expect(args.update.feverC).toBe(37);
|
||||
|
||||
@@ -28,7 +28,13 @@ describe("summarizeIllnessRetrospective", () => {
|
||||
it("counts episodes, resolved, by-month, by-type", () => {
|
||||
const out = summarizeIllnessRetrospective([
|
||||
ep({ id: "a", onsetDay: "2026-01-05", type: "INFECTION" }),
|
||||
ep({ id: "b", onsetDay: "2026-11-20", type: "INFECTION", resolved: false, recoveryGapDays: null }),
|
||||
ep({
|
||||
id: "b",
|
||||
onsetDay: "2026-11-20",
|
||||
type: "INFECTION",
|
||||
resolved: false,
|
||||
recoveryGapDays: null,
|
||||
}),
|
||||
ep({ id: "c", onsetDay: "2026-11-02", type: "ALLERGY" }),
|
||||
]);
|
||||
expect(out.episodeCount).toBe(3);
|
||||
|
||||
@@ -94,7 +94,9 @@ describe("notifySafetyFloor", () => {
|
||||
it("stamps the ledger anchor (keyed by reason) before dispatching", async () => {
|
||||
await notifySafetyFloor({ userId: "u9", decision: bpHigh });
|
||||
expect(createMock).toHaveBeenCalledTimes(1);
|
||||
expect(createMock.mock.calls[0][0].data.reason).toContain("bp_hypertensive");
|
||||
expect(createMock.mock.calls[0][0].data.reason).toContain(
|
||||
"bp_hypertensive",
|
||||
);
|
||||
expect(createMock.mock.calls[0][0].data.eventType).toBe("SYSTEM_ALERT");
|
||||
});
|
||||
|
||||
|
||||
@@ -81,7 +81,9 @@ export async function computeEpisodeCorrelation(
|
||||
const end = episode.resolvedAt ?? now;
|
||||
|
||||
// Window seams (UTC instants; the day keys are read in the user's tz).
|
||||
const preOnsetStart = new Date(onset.getTime() - PRE_ONSET_LOOKBACK_DAYS * MS_PER_DAY);
|
||||
const preOnsetStart = new Date(
|
||||
onset.getTime() - PRE_ONSET_LOOKBACK_DAYS * MS_PER_DAY,
|
||||
);
|
||||
const baselineEnd = preOnsetStart; // baseline ends where the lookback starts
|
||||
const baselineStart = new Date(
|
||||
baselineEnd.getTime() - BASELINE_WINDOW_DAYS * MS_PER_DAY,
|
||||
@@ -106,8 +108,24 @@ export async function computeEpisodeCorrelation(
|
||||
ILLNESS_SCAN_TYPES.map((type) =>
|
||||
limit(async () => {
|
||||
const [baseline, episodeWin] = await Promise.all([
|
||||
readWindowMeans(userId, type, baselineStart, baselineEnd, coverage, tz, now),
|
||||
readWindowMeans(userId, type, preOnsetStart, end, coverage, tz, now),
|
||||
readWindowMeans(
|
||||
userId,
|
||||
type,
|
||||
baselineStart,
|
||||
baselineEnd,
|
||||
coverage,
|
||||
tz,
|
||||
now,
|
||||
),
|
||||
readWindowMeans(
|
||||
userId,
|
||||
type,
|
||||
preOnsetStart,
|
||||
end,
|
||||
coverage,
|
||||
tz,
|
||||
now,
|
||||
),
|
||||
]);
|
||||
return { type, baseline, episodeWin };
|
||||
}),
|
||||
@@ -120,8 +138,10 @@ export async function computeEpisodeCorrelation(
|
||||
let anyLive = false;
|
||||
let anyDay = false;
|
||||
for (const { type, baseline, episodeWin } of perType) {
|
||||
if (baseline.points.length === 0 && episodeWin.points.length === 0) continue;
|
||||
if (baseline.source === "live" || episodeWin.source === "live") anyLive = true;
|
||||
if (baseline.points.length === 0 && episodeWin.points.length === 0)
|
||||
continue;
|
||||
if (baseline.source === "live" || episodeWin.source === "live")
|
||||
anyLive = true;
|
||||
if (baseline.source === "DAY" || episodeWin.source === "DAY") anyDay = true;
|
||||
series.push({
|
||||
type,
|
||||
@@ -129,7 +149,10 @@ export async function computeEpisodeCorrelation(
|
||||
episodeDays: episodeWin.points.map((p) => ({ day: p.day, mean: p.mean })),
|
||||
// Per-day max over the episode window — the fever red-flag prefers it so
|
||||
// an evening spike averaged toward normal in the daily mean is not masked.
|
||||
episodeDayMax: episodeWin.points.map((p) => ({ day: p.day, mean: p.max })),
|
||||
episodeDayMax: episodeWin.points.map((p) => ({
|
||||
day: p.day,
|
||||
mean: p.max,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -173,7 +196,11 @@ async function readWindowMeans(
|
||||
Math.ceil((to.getTime() - from.getTime()) / MS_PER_DAY),
|
||||
);
|
||||
const resolved = await readBestGranularityRollups(userId, type, windowDays);
|
||||
if (resolved && resolved.granularity === "DAY" && resolved.rows.length > 0) {
|
||||
if (
|
||||
resolved &&
|
||||
resolved.granularity === "DAY" &&
|
||||
resolved.rows.length > 0
|
||||
) {
|
||||
const fromKey = dayKeyForUserTz(from, tz);
|
||||
// DAY buckets are minted at the UTC midnight of the user-tz day, so
|
||||
// keying `bucketStart` through the user tz is exact.
|
||||
|
||||
@@ -76,19 +76,20 @@ export const MIN_EPISODE_COVERAGE_DAYS = 4;
|
||||
* Weight/glucose have no single illness-adverse direction → omitted (their
|
||||
* deviation magnitude is still surfaced, direction stays neutral).
|
||||
*/
|
||||
export const ADVERSE_DIRECTION: Partial<Record<MeasurementType, "up" | "down">> =
|
||||
{
|
||||
RESTING_HEART_RATE: "up",
|
||||
PULSE: "up",
|
||||
BODY_TEMPERATURE: "up",
|
||||
SKIN_TEMPERATURE: "up",
|
||||
RESPIRATORY_RATE: "up",
|
||||
BLOOD_PRESSURE_SYS: "up",
|
||||
BLOOD_PRESSURE_DIA: "up",
|
||||
HEART_RATE_VARIABILITY: "down",
|
||||
RECOVERY_SCORE: "down",
|
||||
OXYGEN_SATURATION: "down",
|
||||
};
|
||||
export const ADVERSE_DIRECTION: Partial<
|
||||
Record<MeasurementType, "up" | "down">
|
||||
> = {
|
||||
RESTING_HEART_RATE: "up",
|
||||
PULSE: "up",
|
||||
BODY_TEMPERATURE: "up",
|
||||
SKIN_TEMPERATURE: "up",
|
||||
RESPIRATORY_RATE: "up",
|
||||
BLOOD_PRESSURE_SYS: "up",
|
||||
BLOOD_PRESSURE_DIA: "up",
|
||||
HEART_RATE_VARIABILITY: "down",
|
||||
RECOVERY_SCORE: "down",
|
||||
OXYGEN_SATURATION: "down",
|
||||
};
|
||||
|
||||
/**
|
||||
* Vitals scanned by the illness engine. Superset of the typical-range set
|
||||
@@ -316,7 +317,14 @@ export function computeIllnessCorrelation(
|
||||
// Only vitals with a trustworthy own-baseline band participate.
|
||||
const banded = input.series
|
||||
.map((s) => ({ series: s, band: bandFor(s) }))
|
||||
.filter((b): b is { series: VitalSeries; band: { center: number; spread: number } } => b.band !== null);
|
||||
.filter(
|
||||
(
|
||||
b,
|
||||
): b is {
|
||||
series: VitalSeries;
|
||||
band: { center: number; spread: number };
|
||||
} => b.band !== null,
|
||||
);
|
||||
|
||||
const inputs = banded.map((b) => String(b.series.type));
|
||||
const provenance = {
|
||||
@@ -447,8 +455,12 @@ export function computeIllnessCorrelation(
|
||||
return buildOk<IllnessCorrelationValue>({
|
||||
value: {
|
||||
episodeId: input.episodeId,
|
||||
preOnset: preOnset.sort((a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd)),
|
||||
nadir: nadir.sort((a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd)),
|
||||
preOnset: preOnset.sort(
|
||||
(a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd),
|
||||
),
|
||||
nadir: nadir.sort(
|
||||
(a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd),
|
||||
),
|
||||
returns,
|
||||
recoveryGapDays,
|
||||
feltBetterDay: window.feltBetterDay,
|
||||
@@ -526,7 +538,10 @@ function detectRedFlags(input: IllnessCorrelationInput): IllnessRedFlag[] {
|
||||
}
|
||||
for (const p of input.dayLogFever ?? []) {
|
||||
if (!inActive(p)) continue;
|
||||
feverByDay.set(p.day, Math.max(feverByDay.get(p.day) ?? -Infinity, p.feverC));
|
||||
feverByDay.set(
|
||||
p.day,
|
||||
Math.max(feverByDay.get(p.day) ?? -Infinity, p.feverC),
|
||||
);
|
||||
}
|
||||
if (feverByDay.size > 0) {
|
||||
const fevPoints: VitalDayPoint[] = [...feverByDay.entries()].map(
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
* dropped silently.
|
||||
*/
|
||||
import { prisma } from "@/lib/db";
|
||||
import {
|
||||
decryptFromBytes,
|
||||
encryptToBytes,
|
||||
} from "@/lib/ai/coach/bytes-codec";
|
||||
import { decryptFromBytes, encryptToBytes } from "@/lib/ai/coach/bytes-codec";
|
||||
import type { IllnessDayLogInput } from "@/lib/validations/illness";
|
||||
import { dayLogSymptomInclude, toIllnessDayLogDTO } from "@/lib/illness/dto";
|
||||
import type { IllnessDayLogDTO } from "@/lib/illness/dto";
|
||||
|
||||
@@ -86,7 +86,8 @@ export async function getActiveIllnessEpisodes(
|
||||
// `findMany`. Dedupe them to a single read per request. An explicit client
|
||||
// (a test stub or a transaction) bypasses the memo so its query is never
|
||||
// served a default-client cached result.
|
||||
if (client !== defaultPrisma) return readActiveIllnessEpisodes(userId, asOf, client);
|
||||
if (client !== defaultPrisma)
|
||||
return readActiveIllnessEpisodes(userId, asOf, client);
|
||||
return memoizePerRequest(
|
||||
`illness-active-episodes:${userId}:${asOf.getTime()}`,
|
||||
() => readActiveIllnessEpisodes(userId, asOf, client),
|
||||
|
||||
Reference in new issue
Block a user