feat: implement terminal authentication bootstrap and integrate into ScanTerminalDashboard
This commit is contained in:
+40
@@ -1332,6 +1332,46 @@ export function runTests() {
|
||||
"MGM series should not mix METAR airportCurrent points into the MGM airport-station line",
|
||||
);
|
||||
|
||||
const ankaraMgmWithMetarLabel = __buildTemperatureChartDataForTest(
|
||||
{
|
||||
city: "ankara",
|
||||
local_date: "2026-05-29",
|
||||
local_time: "18:48",
|
||||
tz_offset_seconds: 3 * 60 * 60,
|
||||
current_temp: 14,
|
||||
airport: "LTAC",
|
||||
} as any,
|
||||
{
|
||||
localTime: "18:48",
|
||||
times: [],
|
||||
temps: [],
|
||||
airportPrimary: {
|
||||
source_code: "mgm",
|
||||
source_label: "METAR",
|
||||
temp: 14,
|
||||
obs_time: "2026-05-29T15:48:00Z",
|
||||
},
|
||||
airportCurrent: {
|
||||
source_code: "metar",
|
||||
source_label: "METAR",
|
||||
temp: 17,
|
||||
obs_time: "18:20",
|
||||
},
|
||||
airportPrimaryTodayObs: [
|
||||
{ time: "2026-05-29T15:00:00Z", temp: 14 },
|
||||
{ time: "2026-05-29T15:30:00Z", temp: 15 },
|
||||
],
|
||||
metarTodayObs: [
|
||||
{ time: "2026-05-29T15:20:00Z", temp: 17 },
|
||||
],
|
||||
} as any,
|
||||
"1D",
|
||||
);
|
||||
const ankaraMgmSeries = seriesByKey(ankaraMgmWithMetarLabel.series as any, "madis") as any;
|
||||
const ankaraMetarSeries = seriesByKey(ankaraMgmWithMetarLabel.series as any, "metar") as any;
|
||||
assert(ankaraMgmSeries?.label === "MGM", "Ankara MGM airport-primary series should be labeled MGM even if payload source_label says METAR");
|
||||
assert(ankaraMetarSeries?.label === "METAR", "Ankara METAR backup series should keep the METAR label");
|
||||
|
||||
const chengduMergedHourly = __mergePatchIntoHourlyForTest(
|
||||
{
|
||||
localTime: "05:25",
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import {
|
||||
loadTerminalAuthProfile,
|
||||
type TerminalAuthProfilePayload,
|
||||
} from "@/components/dashboard/scan-terminal/terminal-auth-bootstrap";
|
||||
|
||||
function assert(condition: unknown, message: string) {
|
||||
if (!condition) throw new Error(message);
|
||||
}
|
||||
|
||||
function deferred<T>() {
|
||||
let resolve!: (value: T) => void;
|
||||
let reject!: (reason?: unknown) => void;
|
||||
const promise = new Promise<T>((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
return { promise, reject, resolve };
|
||||
}
|
||||
|
||||
async function flushMicrotasks() {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
export async function runTests() {
|
||||
const slowCookieProfile = deferred<TerminalAuthProfilePayload>();
|
||||
const fastSession = deferred<{ data: { session: { access_token: string } } }>();
|
||||
const calls: string[] = [];
|
||||
|
||||
const resultPromise = loadTerminalAuthProfile({
|
||||
hasSupabasePublicEnv: true,
|
||||
getSession: () => {
|
||||
calls.push("getSession");
|
||||
return fastSession.promise;
|
||||
},
|
||||
loadAuthProfile: (accessToken) => {
|
||||
const token = String(accessToken || "");
|
||||
calls.push(token ? `profile:${token}` : "profile:cookie");
|
||||
if (!token) return slowCookieProfile.promise;
|
||||
return Promise.resolve({
|
||||
authenticated: true,
|
||||
user_id: "bearer-user",
|
||||
subscription_active: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await flushMicrotasks();
|
||||
assert(
|
||||
calls.includes("profile:cookie") && calls.includes("getSession"),
|
||||
"terminal auth bootstrap should start cookie profile and Supabase session in parallel",
|
||||
);
|
||||
|
||||
fastSession.resolve({ data: { session: { access_token: "fast-token" } } });
|
||||
const result = await resultPromise;
|
||||
assert(
|
||||
calls.includes("profile:fast-token"),
|
||||
"terminal auth bootstrap should retry auth profile with the Supabase bearer token",
|
||||
);
|
||||
assert(
|
||||
result.authenticated === true && result.user_id === "bearer-user",
|
||||
"terminal auth bootstrap should not wait for a slow cookie profile when bearer auth succeeds",
|
||||
);
|
||||
|
||||
const slowSession = deferred<{ data: { session: { access_token: string } | null } }>();
|
||||
const cookieOnlyResult = await loadTerminalAuthProfile({
|
||||
hasSupabasePublicEnv: true,
|
||||
getSession: () => slowSession.promise,
|
||||
loadAuthProfile: (accessToken) => {
|
||||
assert(!accessToken, "authenticated cookie profile should finish without requiring bearer profile");
|
||||
return Promise.resolve({
|
||||
authenticated: true,
|
||||
user_id: "cookie-user",
|
||||
subscription_active: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
assert(
|
||||
cookieOnlyResult.user_id === "cookie-user",
|
||||
"terminal auth bootstrap should accept an authenticated cookie profile immediately",
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user