mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
refactor(integrations): read the OAuth redirect URIs through the env helpers
The seven integration clients now read their redirect URI and the app URL through envValue/envOr instead of a local ?.trim() ||. The empty-env guard drops its pending entry and floors its walk, and proves its matcher still fires on a real client with the old read put back.
This commit is contained in:
1 parent
903f0a9a22
commit
cc60b82d84
8 files changed
+45
-38
No files matched your search
@@ -38,16 +38,6 @@ const SRC = join(process.cwd(), "src");
|
||||
const NULLISH_ENV_FALLBACK =
|
||||
/process\.env(?:\.[A-Za-z_][A-Za-z0-9_]*|\[\s*["'`][A-Za-z_][A-Za-z0-9_]*["'`]\s*\])(?:\?\.[A-Za-z_]+\((?:[^()]|\([^()]*\))*\))*\s*\?\?/g;
|
||||
|
||||
/**
|
||||
* Files that still carry the pattern because another change owns them.
|
||||
* Each entry fails T3 once the file no longer matches, so the list can only
|
||||
* shrink.
|
||||
*/
|
||||
const PENDING: Readonly<Record<string, string>> = {
|
||||
"lib/withings/client.ts":
|
||||
"WITHINGS_REDIRECT_URI ?? derived callback; the integration clients are being reworked in a parallel change that owns this file",
|
||||
};
|
||||
|
||||
function sourceFiles(): string[] {
|
||||
return walkSourceFiles(SRC, { floor: 3000 })
|
||||
.filter((rel) => !rel.startsWith("generated/"))
|
||||
@@ -88,20 +78,30 @@ describe("an empty environment variable counts as unset", () => {
|
||||
});
|
||||
|
||||
it("T2 — no source file defaults a process.env read with ??", () => {
|
||||
const found = offenders().filter((rel) => !(rel in PENDING));
|
||||
expect(
|
||||
found,
|
||||
offenders(),
|
||||
"Read these through envValue/envOr/envFlag from @/lib/env. Compose " +
|
||||
"passes an unset variable as the empty string, and ?? keeps it.",
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("T3 — every pending entry still matches, so the list only shrinks", () => {
|
||||
const current = new Set(offenders());
|
||||
const stale = Object.keys(PENDING).filter((rel) => !current.has(rel));
|
||||
expect(
|
||||
stale,
|
||||
"No longer carries the pattern; drop the entry from PENDING.",
|
||||
).toEqual([]);
|
||||
it("T3 — the sweep read the tree and the matcher fires on real source", () => {
|
||||
// An empty offender list proves nothing if the narrowed walk found no
|
||||
// files, or if the matcher no longer fires on what the tree actually
|
||||
// holds. Floor the narrowed set, then put the pre-fix read back into a
|
||||
// real client and require the matcher to find it there.
|
||||
const files = sourceFiles();
|
||||
expect(files.length).toBeGreaterThan(2400);
|
||||
expect(files).toContain("lib/withings/client.ts");
|
||||
const real = readFileSync(join(SRC, "lib/withings/client.ts"), "utf8");
|
||||
expect([...real.matchAll(NULLISH_ENV_FALLBACK)]).toEqual([]);
|
||||
const reverted = real.replace(
|
||||
/envOr\(\s*"WITHINGS_REDIRECT_URI",/,
|
||||
"process.env.WITHINGS_REDIRECT_URI ?? (",
|
||||
);
|
||||
expect(reverted).not.toBe(real);
|
||||
expect([...reverted.matchAll(NULLISH_ENV_FALLBACK)].length).toBeGreaterThan(
|
||||
0,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -42,6 +42,7 @@ import { safeFetch } from "@/lib/safe-fetch";
|
||||
import { canonicalDailyTimestamp } from "@/lib/measurements/consolidation-tz";
|
||||
import { zonedWallClockToUtc } from "@/lib/tz/wall-clock";
|
||||
import { FitbitApiError, classifyFitbitResponse } from "./response-classifier";
|
||||
import { envValue } from "@/lib/env";
|
||||
|
||||
/** Classic Fitbit Web API base. */
|
||||
export const FITBIT_API_BASE = "https://api.fitbit.com";
|
||||
@@ -80,8 +81,8 @@ export function getFitbitRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises an unset var as an empty string, which must fall through to
|
||||
// the derived URI rather than read as "not configured".
|
||||
const explicit = process.env.FITBIT_REDIRECT_URI?.trim() || undefined;
|
||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim() || undefined;
|
||||
const explicit = envValue("FITBIT_REDIRECT_URI");
|
||||
const appUrl = envValue("NEXT_PUBLIC_APP_URL");
|
||||
const raw =
|
||||
explicit ?? (appUrl ? `${appUrl}/api/fitbit/callback` : undefined);
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import type {
|
||||
GoogleHealthDataType,
|
||||
GoogleHealthRollupPoint,
|
||||
} from "./mappers";
|
||||
import { envValue } from "@/lib/env";
|
||||
|
||||
export * from "./mappers";
|
||||
|
||||
@@ -150,8 +151,8 @@ export function getGoogleHealthRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises an unset var as an empty string, which must fall through to
|
||||
// the derived URI rather than read as "not configured".
|
||||
const explicit = process.env.GOOGLE_HEALTH_REDIRECT_URI?.trim() || undefined;
|
||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL?.trim() || undefined;
|
||||
const explicit = envValue("GOOGLE_HEALTH_REDIRECT_URI");
|
||||
const appUrl = envValue("NEXT_PUBLIC_APP_URL");
|
||||
const raw =
|
||||
explicit ?? (appUrl ? `${appUrl}/api/google-health/callback` : undefined);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import { canonicalDailyTimestamp } from "@/lib/measurements/consolidation-tz";
|
||||
import { dayDiff } from "@/lib/cycle/day-math";
|
||||
import { safeFetch } from "@/lib/safe-fetch";
|
||||
import { OuraApiError, classifyOuraResponse } from "./response-classifier";
|
||||
import { envOr, envValue } from "@/lib/env";
|
||||
|
||||
const OURA_API_BASE = "https://api.ouraring.com";
|
||||
const OURA_OAUTH_AUTH_URL = "https://cloud.ouraring.com/oauth/authorize";
|
||||
@@ -44,9 +45,9 @@ export function getOuraCredentials(): OuraCredentials | null {
|
||||
export function getOuraRedirectUri(): string {
|
||||
// An empty or blank value counts as unset (the compose whitelist
|
||||
// materialises an unset var as an empty string).
|
||||
return (
|
||||
process.env.OURA_REDIRECT_URI?.trim() ||
|
||||
`${process.env.NEXT_PUBLIC_APP_URL?.trim()}/api/oura/callback`
|
||||
return envOr(
|
||||
"OURA_REDIRECT_URI",
|
||||
`${envValue("NEXT_PUBLIC_APP_URL")}/api/oura/callback`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import type { Prisma } from "@/generated/prisma/client";
|
||||
import type { WorkoutSportType } from "@/lib/validations/workout";
|
||||
import { PolarApiError, classifyPolarResponse } from "./response-classifier";
|
||||
import { mapPolarSportType } from "./sport-map";
|
||||
import { envOr, envValue } from "@/lib/env";
|
||||
|
||||
const POLAR_API_BASE = "https://www.polaraccesslink.com";
|
||||
const POLAR_OAUTH_AUTH_URL = "https://flow.polar.com/oauth2/authorization";
|
||||
@@ -57,9 +58,9 @@ export function getPolarRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises an unset var as an empty string, which must still fall
|
||||
// through to the derived URI.
|
||||
return (
|
||||
process.env.POLAR_REDIRECT_URI?.trim() ||
|
||||
`${process.env.NEXT_PUBLIC_APP_URL?.trim()}/api/polar/callback`
|
||||
return envOr(
|
||||
"POLAR_REDIRECT_URI",
|
||||
`${envValue("NEXT_PUBLIC_APP_URL")}/api/polar/callback`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import type { Prisma } from "@/generated/prisma/client";
|
||||
import { StravaApiError, classifyStravaResponse } from "./response-classifier";
|
||||
import { mapStravaSportType } from "./sport-map";
|
||||
import type { WorkoutSportType } from "@/lib/validations/workout";
|
||||
import { envOr, envValue } from "@/lib/env";
|
||||
|
||||
const STRAVA_API_BASE = "https://www.strava.com/api/v3";
|
||||
const STRAVA_OAUTH_AUTH_URL = "https://www.strava.com/oauth/authorize";
|
||||
@@ -55,9 +56,9 @@ export function getStravaRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises an unset var as an empty string, which must still fall
|
||||
// through to the derived URI.
|
||||
return (
|
||||
process.env.STRAVA_REDIRECT_URI?.trim() ||
|
||||
`${process.env.NEXT_PUBLIC_APP_URL?.trim()}/api/strava/callback`
|
||||
return envOr(
|
||||
"STRAVA_REDIRECT_URI",
|
||||
`${envValue("NEXT_PUBLIC_APP_URL")}/api/strava/callback`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { getEvent } from "@/lib/logging/context";
|
||||
import { safeFetch } from "@/lib/safe-fetch";
|
||||
import { reconstructContiguousSleepTimeline } from "@/lib/sleep/reconstruct-timeline";
|
||||
import { WhoopApiError, classifyWhoopResponse } from "./response-classifier";
|
||||
import { envOr, envValue } from "@/lib/env";
|
||||
|
||||
const WHOOP_API_BASE = "https://api.prod.whoop.com/developer";
|
||||
const WHOOP_OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth";
|
||||
@@ -36,9 +37,9 @@ export function getWhoopRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises the var as an empty string when unset, which must still fall
|
||||
// through to the derived URI.
|
||||
return (
|
||||
process.env.WHOOP_REDIRECT_URI?.trim() ||
|
||||
`${process.env.NEXT_PUBLIC_APP_URL?.trim()}/api/whoop/callback`
|
||||
return envOr(
|
||||
"WHOOP_REDIRECT_URI",
|
||||
`${envValue("NEXT_PUBLIC_APP_URL")}/api/whoop/callback`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
WithingsApiError,
|
||||
classifyWithingsResponse,
|
||||
} from "./response-classifier";
|
||||
import { envOr, envValue } from "@/lib/env";
|
||||
|
||||
const WITHINGS_OAUTH_URL =
|
||||
"https://account.withings.com/oauth2_user/authorize2";
|
||||
@@ -24,9 +25,9 @@ export function getWithingsRedirectUri(): string {
|
||||
// An empty or blank value counts as unset: the compose whitelist
|
||||
// materialises an unset var as an empty string, which must fall through to
|
||||
// the derived URI rather than go out as `redirect_uri=`.
|
||||
return (
|
||||
process.env.WITHINGS_REDIRECT_URI?.trim() ||
|
||||
`${process.env.NEXT_PUBLIC_APP_URL?.trim()}/api/withings/callback`
|
||||
return envOr(
|
||||
"WITHINGS_REDIRECT_URI",
|
||||
`${envValue("NEXT_PUBLIC_APP_URL")}/api/withings/callback`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user