97 lines
3.6 KiB
TypeScript
97 lines
3.6 KiB
TypeScript
import { BirthProfileTimezoneError, resolveMissingBirthTimezoneOffset } from "./birth-profile-timezone.ts";
|
|
import {
|
|
resolveServerOwnedChartBirth,
|
|
unresolvedChartBirth,
|
|
type ChartBirthFailureReason,
|
|
type ServerOwnedChartBirth,
|
|
} from "./chart-birth-truth.ts";
|
|
import type { ChartViewProfileInput } from "./chart-view-mapper.ts";
|
|
|
|
export type ChartViewProfileRead =
|
|
| { ok: true; profile: ChartViewProfileInput; birth: ServerOwnedChartBirth }
|
|
| { ok: false; failure: ChartBirthFailureReason; birth: ServerOwnedChartBirth };
|
|
|
|
function text(value: unknown): string | undefined {
|
|
if (typeof value !== "string") return undefined;
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
}
|
|
|
|
function isTimezoneFailure(error: unknown): boolean {
|
|
return error instanceof BirthProfileTimezoneError
|
|
|| (error instanceof Error && error.name === "BirthProfileTimezoneError");
|
|
}
|
|
|
|
function chartInput(row: unknown, birth: ServerOwnedChartBirth): ChartViewProfileInput | null {
|
|
if (!birth.chartable || birth.date == null || birth.time == null || birth.timezoneOffset == null) return null;
|
|
const source = row !== null && typeof row === "object" && !Array.isArray(row)
|
|
? row as Record<string, unknown>
|
|
: {};
|
|
const latitude = typeof source.latitude === "number" ? source.latitude : Number(source.latitude);
|
|
const longitude = typeof source.longitude === "number" ? source.longitude : Number(source.longitude);
|
|
if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return null;
|
|
return {
|
|
name: text(source.name),
|
|
date: birth.date,
|
|
time: birth.time,
|
|
placeLabel: text(source.birth_place_label),
|
|
latitude,
|
|
longitude,
|
|
timezoneOffset: birth.timezoneOffset,
|
|
timezoneId: birth.timezoneId ?? undefined,
|
|
ayanamsa: typeof source.ayanamsa === "string" ? source.ayanamsa : undefined,
|
|
birthTimeStatus: birth.status ?? undefined,
|
|
};
|
|
}
|
|
|
|
export async function prepareChartViewProfile(input: {
|
|
row: unknown;
|
|
queryError?: unknown;
|
|
resolveTimezone?: typeof resolveMissingBirthTimezoneOffset;
|
|
}): Promise<ChartViewProfileRead> {
|
|
if (input.queryError) {
|
|
return {
|
|
ok: false,
|
|
failure: "profile_query_error",
|
|
birth: unresolvedChartBirth("profile_query_error"),
|
|
};
|
|
}
|
|
const stored = resolveServerOwnedChartBirth(input.row);
|
|
if (stored.failure === "adopted_calculation_incomplete") {
|
|
return { ok: false, failure: stored.failure, birth: stored };
|
|
}
|
|
const resolveTimezone = input.resolveTimezone ?? resolveMissingBirthTimezoneOffset;
|
|
let resolved: unknown;
|
|
try {
|
|
resolved = await resolveTimezone(input.row, { useActiveDate: true });
|
|
} catch (error) {
|
|
if (!isTimezoneFailure(error)) throw error;
|
|
return {
|
|
ok: false,
|
|
failure: "timezone_resolver_failure",
|
|
birth: {
|
|
...stored,
|
|
failure: "timezone_resolver_failure",
|
|
chartable: false,
|
|
timezoneOffset: null,
|
|
},
|
|
};
|
|
}
|
|
const filled = resolveServerOwnedChartBirth(resolved);
|
|
// Keep the stored-row fingerprint so account GET and chart-view name the
|
|
// same profile even when a missing declared offset was filled in memory.
|
|
const birth = { ...filled, fingerprint: stored.fingerprint };
|
|
if (birth.failure === "adopted_calculation_incomplete") {
|
|
return { ok: false, failure: birth.failure, birth };
|
|
}
|
|
const profile = chartInput(resolved, birth);
|
|
if (!profile || birth.failure) {
|
|
return {
|
|
ok: false,
|
|
failure: birth.failure ?? "profile_incomplete",
|
|
birth: { ...birth, failure: birth.failure ?? "profile_incomplete", chartable: false },
|
|
};
|
|
}
|
|
return { ok: true, profile, birth };
|
|
}
|