mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 06:52:04 +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
@@ -147,7 +147,9 @@ describe("clear-on-taken push", () => {
|
||||
expect(sendNotificationMock).toHaveBeenCalledTimes(1);
|
||||
const body = JSON.parse(sendNotificationMock.mock.calls[0][1] as string);
|
||||
expect(body.type).toBe("clear");
|
||||
expect(body.tag).toBe(medicationDoseTag("med-1", "2026-06-18T07:00:00.000Z"));
|
||||
expect(body.tag).toBe(
|
||||
medicationDoseTag("med-1", "2026-06-18T07:00:00.000Z"),
|
||||
);
|
||||
expect(body.badge).toBe(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -69,8 +69,14 @@ interface DispatchLocalisedOptions {
|
||||
}
|
||||
|
||||
function isLocale(value: string | null | undefined): value is Locale {
|
||||
return value === "de" || value === "en" || value === "fr" ||
|
||||
value === "es" || value === "it" || value === "pl";
|
||||
return (
|
||||
value === "de" ||
|
||||
value === "en" ||
|
||||
value === "fr" ||
|
||||
value === "es" ||
|
||||
value === "it" ||
|
||||
value === "pl"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -200,7 +200,9 @@ export async function dispatchMedicationIntakeSync(
|
||||
});
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
getEvent()?.addWarning(`medication_intake_sync_dispatch_failed: ${message}`);
|
||||
getEvent()?.addWarning(
|
||||
`medication_intake_sync_dispatch_failed: ${message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,8 +195,12 @@ describe("loadApnsConfig — all-or-none env-var guard", () => {
|
||||
setEnv({ ...VALID_ENV, APNS_KEY: collapsed });
|
||||
const config = loadApnsConfig();
|
||||
expect(config).toBeTruthy();
|
||||
expect(config?.signingKey.startsWith("-----BEGIN PRIVATE KEY-----\n")).toBe(true);
|
||||
expect(config?.signingKey.endsWith("\n-----END PRIVATE KEY-----")).toBe(true);
|
||||
expect(config?.signingKey.startsWith("-----BEGIN PRIVATE KEY-----\n")).toBe(
|
||||
true,
|
||||
);
|
||||
expect(config?.signingKey.endsWith("\n-----END PRIVATE KEY-----")).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts a bare base64 body without BEGIN/END markers", () => {
|
||||
@@ -207,13 +211,16 @@ describe("loadApnsConfig — all-or-none env-var guard", () => {
|
||||
setEnv({ ...VALID_ENV, APNS_KEY: bareBase64 });
|
||||
const config = loadApnsConfig();
|
||||
expect(config).toBeTruthy();
|
||||
expect(config?.signingKey.startsWith("-----BEGIN PRIVATE KEY-----\n")).toBe(true);
|
||||
expect(config?.signingKey.startsWith("-----BEGIN PRIVATE KEY-----\n")).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("returns null + warns when APNS_KEY does not parse as an asymmetric key", () => {
|
||||
setEnv({
|
||||
...VALID_ENV,
|
||||
APNS_KEY: "-----BEGIN PRIVATE KEY-----\\nNOTAREALKEY\\n-----END PRIVATE KEY-----",
|
||||
APNS_KEY:
|
||||
"-----BEGIN PRIVATE KEY-----\\nNOTAREALKEY\\n-----END PRIVATE KEY-----",
|
||||
});
|
||||
const config = loadApnsConfig();
|
||||
expect(config).toBeNull();
|
||||
@@ -229,7 +236,8 @@ describe("loadApnsConfig — all-or-none env-var guard", () => {
|
||||
APNS_TEAM_ID: VALID_ENV.APNS_TEAM_ID,
|
||||
APNS_BUNDLE_ID: VALID_ENV.APNS_BUNDLE_ID,
|
||||
// Both set on purpose — B64 takes precedence.
|
||||
APNS_KEY: "-----BEGIN PRIVATE KEY-----\\nBROKEN\\n-----END PRIVATE KEY-----",
|
||||
APNS_KEY:
|
||||
"-----BEGIN PRIVATE KEY-----\\nBROKEN\\n-----END PRIVATE KEY-----",
|
||||
APNS_KEY_B64: b64,
|
||||
});
|
||||
const config = loadApnsConfig();
|
||||
@@ -508,7 +516,13 @@ describe("sendViaApns — dispatcher fan-out", () => {
|
||||
// First send (production gateway): rejected.
|
||||
sendMock.mockResolvedValueOnce({
|
||||
sent: [],
|
||||
failed: [{ device: "tok-a", status: 403, response: { reason: "BadEnvironmentKeyInToken" } }],
|
||||
failed: [
|
||||
{
|
||||
device: "tok-a",
|
||||
status: 403,
|
||||
response: { reason: "BadEnvironmentKeyInToken" },
|
||||
},
|
||||
],
|
||||
});
|
||||
// Second send (sandbox gateway): success.
|
||||
sendMock.mockResolvedValueOnce({
|
||||
@@ -536,7 +550,13 @@ describe("sendViaApns — dispatcher fan-out", () => {
|
||||
] as never);
|
||||
sendMock.mockResolvedValueOnce({
|
||||
sent: [],
|
||||
failed: [{ device: "tok-a", status: 410, response: { reason: "BadDeviceToken" } }],
|
||||
failed: [
|
||||
{
|
||||
device: "tok-a",
|
||||
status: 410,
|
||||
response: { reason: "BadDeviceToken" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const r = await sendViaApns("u-1", {
|
||||
@@ -703,25 +723,31 @@ describe("sendViaApns — dispatcher fan-out", () => {
|
||||
"WITHINGS_SYNC_FAILED",
|
||||
"SYSTEM_ALERT",
|
||||
"PERSONAL_RECORD",
|
||||
])("eventType %s does NOT set interruption-level (Focus respected)", async (eventType) => {
|
||||
// Every non-MEDICATION_REMINDER event-type must omit the
|
||||
// interruption-level so the system default (`active`) lets Focus
|
||||
// modes — Sleep, Do-Not-Disturb, Personal — silence the alert as
|
||||
// the user expects.
|
||||
vi.mocked(prisma.device.findMany).mockResolvedValueOnce([
|
||||
{ id: "d1", apnsToken: "tok-a", apnsEnvironment: "sandbox" },
|
||||
] as never);
|
||||
sendMock.mockResolvedValueOnce({ sent: [{ device: "tok-a" }], failed: [] });
|
||||
await sendViaApns("u-1", {
|
||||
title: "t",
|
||||
message: "m",
|
||||
eventType,
|
||||
});
|
||||
const note = sendMock.mock.calls[0][0];
|
||||
expect(note.interruptionLevel).toBeUndefined();
|
||||
// priority too — only opt in for time-sensitive deliveries.
|
||||
expect(note.priority).toBeUndefined();
|
||||
});
|
||||
])(
|
||||
"eventType %s does NOT set interruption-level (Focus respected)",
|
||||
async (eventType) => {
|
||||
// Every non-MEDICATION_REMINDER event-type must omit the
|
||||
// interruption-level so the system default (`active`) lets Focus
|
||||
// modes — Sleep, Do-Not-Disturb, Personal — silence the alert as
|
||||
// the user expects.
|
||||
vi.mocked(prisma.device.findMany).mockResolvedValueOnce([
|
||||
{ id: "d1", apnsToken: "tok-a", apnsEnvironment: "sandbox" },
|
||||
] as never);
|
||||
sendMock.mockResolvedValueOnce({
|
||||
sent: [{ device: "tok-a" }],
|
||||
failed: [],
|
||||
});
|
||||
await sendViaApns("u-1", {
|
||||
title: "t",
|
||||
message: "m",
|
||||
eventType,
|
||||
});
|
||||
const note = sendMock.mock.calls[0][0];
|
||||
expect(note.interruptionLevel).toBeUndefined();
|
||||
// priority too — only opt in for time-sensitive deliveries.
|
||||
expect(note.priority).toBeUndefined();
|
||||
},
|
||||
);
|
||||
|
||||
it("forwards explicit interruptionLevel on sendApnsPush", async () => {
|
||||
// Lower-level entry should round-trip the explicit flag — caller
|
||||
|
||||
@@ -33,10 +33,7 @@ vi.mock("@/lib/notifications/senders/push-attempt-record", () => ({
|
||||
recordPushAttempt: (...args: unknown[]) => recordPushAttemptMock(...args),
|
||||
}));
|
||||
|
||||
import {
|
||||
sendViaEmail,
|
||||
resetEmailTransporterForTesting,
|
||||
} from "../email";
|
||||
import { sendViaEmail, resetEmailTransporterForTesting } from "../email";
|
||||
|
||||
const transport = {
|
||||
host: "smtp.example.com",
|
||||
@@ -73,7 +70,10 @@ describe("sendViaEmail", () => {
|
||||
loadEmailConfigMock.mockReturnValue(transport);
|
||||
sendMailMock.mockResolvedValue({ messageId: "1" });
|
||||
|
||||
const result = await sendViaEmail({ recipient: "you@example.com" }, payload());
|
||||
const result = await sendViaEmail(
|
||||
{ recipient: "you@example.com" },
|
||||
payload(),
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
const mail = sendMailMock.mock.calls[0][0];
|
||||
@@ -107,7 +107,10 @@ describe("sendViaEmail", () => {
|
||||
it("soft-skips when SMTP is unconfigured (no channel burn)", async () => {
|
||||
loadEmailConfigMock.mockReturnValue(null);
|
||||
|
||||
const result = await sendViaEmail({ recipient: "you@example.com" }, payload());
|
||||
const result = await sendViaEmail(
|
||||
{ recipient: "you@example.com" },
|
||||
payload(),
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.hardReject).toBe(false);
|
||||
@@ -135,7 +138,10 @@ describe("sendViaEmail", () => {
|
||||
});
|
||||
sendMailMock.mockRejectedValue(err);
|
||||
|
||||
const result = await sendViaEmail({ recipient: "you@example.com" }, payload());
|
||||
const result = await sendViaEmail(
|
||||
{ recipient: "you@example.com" },
|
||||
payload(),
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.hardReject).toBe(true);
|
||||
@@ -146,7 +152,10 @@ describe("sendViaEmail", () => {
|
||||
loadEmailConfigMock.mockReturnValue(transport);
|
||||
sendMailMock.mockRejectedValue(new Error("ECONNREFUSED"));
|
||||
|
||||
const result = await sendViaEmail({ recipient: "you@example.com" }, payload());
|
||||
const result = await sendViaEmail(
|
||||
{ recipient: "you@example.com" },
|
||||
payload(),
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.hardReject).toBe(false);
|
||||
|
||||
@@ -110,7 +110,10 @@ vi.mock("@/lib/telegram", () => ({
|
||||
deleteMessage: hoisted.deleteTelegramMessageMock,
|
||||
}));
|
||||
|
||||
import { sendViaApns, resetApnsForTesting } from "@/lib/notifications/senders/apns";
|
||||
import {
|
||||
sendViaApns,
|
||||
resetApnsForTesting,
|
||||
} from "@/lib/notifications/senders/apns";
|
||||
import { sendViaWebPush } from "@/lib/notifications/senders/web-push";
|
||||
import { sendViaTelegram } from "@/lib/notifications/senders/telegram";
|
||||
import { sendViaNtfy } from "@/lib/notifications/senders/ntfy";
|
||||
|
||||
@@ -106,9 +106,11 @@ describe("ntfy urgent mapping", () => {
|
||||
{ serverUrl: "https://ntfy.example.com", topic: "t" },
|
||||
payload(),
|
||||
);
|
||||
const headers = (safeFetchMock.mock.calls[0][1] as {
|
||||
headers: Record<string, string>;
|
||||
}).headers;
|
||||
const headers = (
|
||||
safeFetchMock.mock.calls[0][1] as {
|
||||
headers: Record<string, string>;
|
||||
}
|
||||
).headers;
|
||||
expect(headers.Priority).toBe("default");
|
||||
expect(headers.Tags).not.toContain("warning");
|
||||
});
|
||||
@@ -119,9 +121,11 @@ describe("ntfy urgent mapping", () => {
|
||||
{ serverUrl: "https://ntfy.example.com", topic: "t" },
|
||||
payload({ urgent: true, discreet: true }),
|
||||
);
|
||||
const headers = (safeFetchMock.mock.calls[0][1] as {
|
||||
headers: Record<string, string>;
|
||||
}).headers;
|
||||
const headers = (
|
||||
safeFetchMock.mock.calls[0][1] as {
|
||||
headers: Record<string, string>;
|
||||
}
|
||||
).headers;
|
||||
expect(headers.Priority).toBe("5");
|
||||
expect(headers.Tags).toBe("reminder");
|
||||
});
|
||||
@@ -153,7 +157,12 @@ describe("webhook urgent mapping", () => {
|
||||
describe("web-push urgent mapping", () => {
|
||||
it("urgent → Urgency:high option + requireInteraction in payload", async () => {
|
||||
findManyMock.mockResolvedValue([
|
||||
{ id: "s1", endpoint: "https://push.example.com/x", p256dh: "a", auth: "b" },
|
||||
{
|
||||
id: "s1",
|
||||
endpoint: "https://push.example.com/x",
|
||||
p256dh: "a",
|
||||
auth: "b",
|
||||
},
|
||||
]);
|
||||
sendNotificationMock.mockResolvedValue(undefined);
|
||||
await sendViaWebPush("user-1", payload({ urgent: true }));
|
||||
@@ -164,7 +173,12 @@ describe("web-push urgent mapping", () => {
|
||||
|
||||
it("non-urgent → no urgency option, requireInteraction false", async () => {
|
||||
findManyMock.mockResolvedValue([
|
||||
{ id: "s1", endpoint: "https://push.example.com/x", p256dh: "a", auth: "b" },
|
||||
{
|
||||
id: "s1",
|
||||
endpoint: "https://push.example.com/x",
|
||||
p256dh: "a",
|
||||
auth: "b",
|
||||
},
|
||||
]);
|
||||
sendNotificationMock.mockResolvedValue(undefined);
|
||||
await sendViaWebPush("user-1", payload());
|
||||
@@ -180,7 +194,12 @@ describe("APNs-less instance degrades gracefully", () => {
|
||||
// that ARE present at their top tier.
|
||||
safeFetchMock.mockResolvedValue({ ok: true, status: 200 });
|
||||
findManyMock.mockResolvedValue([
|
||||
{ id: "s1", endpoint: "https://push.example.com/x", p256dh: "a", auth: "b" },
|
||||
{
|
||||
id: "s1",
|
||||
endpoint: "https://push.example.com/x",
|
||||
p256dh: "a",
|
||||
auth: "b",
|
||||
},
|
||||
]);
|
||||
sendNotificationMock.mockResolvedValue(undefined);
|
||||
|
||||
|
||||
@@ -128,9 +128,10 @@ export async function sendViaWebPush(
|
||||
// v1.18.4 — the Web Push `Urgency` header (RFC 8030) tells the push
|
||||
// service to deliver immediately rather than batching for power. An
|
||||
// urgent event uses `high`; everything else keeps the library default.
|
||||
const sendOptions = payload.urgent === true
|
||||
? ({ urgency: "high" as const } as const)
|
||||
: undefined;
|
||||
const sendOptions =
|
||||
payload.urgent === true
|
||||
? ({ urgency: "high" as const } as const)
|
||||
: undefined;
|
||||
|
||||
let anySuccess = false;
|
||||
const expiredIds: string[] = [];
|
||||
|
||||
@@ -54,7 +54,11 @@ export async function dispatchMedicationIntakeWebClear(
|
||||
if (!subscriptions.length) return;
|
||||
|
||||
const webpush = await import("web-push");
|
||||
webpush.setVapidDetails(config.subject, config.publicKey, config.privateKey);
|
||||
webpush.setVapidDetails(
|
||||
config.subject,
|
||||
config.publicKey,
|
||||
config.privateKey,
|
||||
);
|
||||
|
||||
const badgeCount =
|
||||
typeof input.badgeCount === "number" && Number.isFinite(input.badgeCount)
|
||||
|
||||
Reference in new issue
Block a user