mirror of
https://github.com/tale/headplane.git
synced 2026-07-27 08:08:56 +00:00
87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import canonicals from "~/openapi-canonical-families.json";
|
|
import hashes from "~/openapi-operation-hashes.json";
|
|
import log from "~/utils/log";
|
|
|
|
/**
|
|
* The known API versions based on operation hashes.
|
|
*/
|
|
export type Version = keyof typeof hashes;
|
|
const VERSIONS = Object.keys(hashes) as Version[];
|
|
|
|
/**
|
|
* Detects the closest matching API version using operation hashes.
|
|
* Falls back to the latest known version and emits a warning if unknown.
|
|
*
|
|
* @param observed - A mapping of operation identifiers to their hashes.
|
|
* @returns The detected API version.
|
|
*/
|
|
export function detectApiVersion(observed: Record<string, string> | null): Version {
|
|
if (!observed) {
|
|
const latest = VERSIONS.at(-1)!;
|
|
log.warn("api", "No operation hashes observed, defaulting to version %s", latest);
|
|
return latest;
|
|
}
|
|
|
|
let bestVersion: Version | null = null;
|
|
let bestScore = -1;
|
|
|
|
for (const [version, known] of Object.entries(hashes) as [Version, Record<string, string>][]) {
|
|
let score = 0;
|
|
for (const [op, hash] of Object.entries(observed)) {
|
|
if (known[op] === hash) score++;
|
|
}
|
|
if (score > bestScore) {
|
|
bestVersion = version;
|
|
bestScore = score;
|
|
}
|
|
}
|
|
|
|
if (!bestVersion || bestScore === 0) {
|
|
const latest = VERSIONS.at(-1)!;
|
|
log.warn("api", "Could not determine API version, defaulting to %s", latest);
|
|
return latest;
|
|
}
|
|
|
|
if (bestScore < Object.keys(observed).length) {
|
|
log.warn(
|
|
"api",
|
|
"Partial version match: %d/%d endpoints for version %s",
|
|
bestScore,
|
|
Object.keys(observed).length,
|
|
bestVersion,
|
|
);
|
|
}
|
|
|
|
const canonical = Object.entries(canonicals).find(([_, family]) =>
|
|
family.includes(bestVersion),
|
|
)?.[0] as Version | undefined;
|
|
|
|
if (!canonical) {
|
|
log.warn("api", "Could not canonicalize detected version %s, using as-is", bestVersion);
|
|
|
|
return bestVersion;
|
|
}
|
|
|
|
if (canonical !== bestVersion) {
|
|
log.info(
|
|
"api",
|
|
"Canonicalizing detected version %s → %s (same schema)",
|
|
bestVersion,
|
|
canonical,
|
|
);
|
|
}
|
|
|
|
return canonical;
|
|
}
|
|
|
|
/**
|
|
* Checks if the current version is at least the baseline version.
|
|
*
|
|
* @param current - The current API version.
|
|
* @param baseline - The baseline API version to compare against.
|
|
* @returns True if current is at least baseline, false otherwise.
|
|
*/
|
|
export function isAtLeast(current: Version, baseline: Version) {
|
|
return VERSIONS.indexOf(current) >= VERSIONS.indexOf(baseline);
|
|
}
|