mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
Pull continuous glucose readings from a self-hosted Nightscout instance and store them as immutable BLOOD_GLUCOSE mg/dL measurements (source=NIGHTSCOUT), giving the glucose panel real CGM density. - client over safeFetch: public-host pin by default, relaxed only on the per-user private-network opt-in; redirect pinned manual + timeout - credentials encrypted at rest on User; URL is the connect marker - sync maps SGV entries first-write-wins on (userId,type,source,externalId) - connect/disconnect/status routes: apiHandler + requireAuth + rate limit; connect validates by a live test fetch with clear errors - hourly poll-cohort job registered in the all-queues registry - settings card with URL, token, and the private-network toggle - i18n across all six locales
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
/**
|
|
* Per-user Nightscout connection credentials (v1.17.0).
|
|
*
|
|
* Unlike WHOOP / Fitbit (OAuth, with a dedicated `*Connection` row), Nightscout
|
|
* is a URL + token the user pastes once. Both are stored encrypted on `User`
|
|
* (`nightscoutUrlEncrypted` / `nightscoutTokenEncrypted`) via the fail-closed
|
|
* `*Encrypted` convention; the private-host opt-in is the plaintext boolean
|
|
* `nightscoutAllowPrivateHost`. This helper is the single read+decrypt path the
|
|
* sync + status + connect surfaces share.
|
|
*/
|
|
import { prisma } from "@/lib/db";
|
|
import { decrypt } from "@/lib/crypto";
|
|
|
|
export interface NightscoutCredentials {
|
|
baseUrl: string;
|
|
token: string;
|
|
allowPrivateHost: boolean;
|
|
}
|
|
|
|
/**
|
|
* Fetch and decrypt the user's Nightscout connection. Returns null when the
|
|
* URL is not configured (a token-less, fully-public instance still stores a
|
|
* URL, so the URL is the configured-marker, not the token).
|
|
*/
|
|
export async function getUserNightscoutCredentials(
|
|
userId: string,
|
|
): Promise<NightscoutCredentials | null> {
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: {
|
|
nightscoutUrlEncrypted: true,
|
|
nightscoutTokenEncrypted: true,
|
|
nightscoutAllowPrivateHost: true,
|
|
},
|
|
});
|
|
|
|
if (!user?.nightscoutUrlEncrypted) return null;
|
|
|
|
return {
|
|
baseUrl: decrypt(user.nightscoutUrlEncrypted),
|
|
token: user.nightscoutTokenEncrypted
|
|
? decrypt(user.nightscoutTokenEncrypted)
|
|
: "",
|
|
allowPrivateHost: user.nightscoutAllowPrivateHost,
|
|
};
|
|
}
|