Files
kandev/apps/web/lib/plugins/repository-provider-url-resolution.ts
T

68 lines
2.2 KiB
TypeScript

import { pluginRegistry } from "./registry";
import type { PluginRepositoryProviderRegistration } from "./registry";
import type { RepositoryInspection, RepositoryProviderRegistration } from "./types";
export type InspectedRepositoryProvider = {
provider: PluginRepositoryProviderRegistration;
inspection: RepositoryInspection;
};
export function repositoryProviderMatchesURL(
provider: RepositoryProviderRegistration,
url: string,
): boolean {
if (!provider.matchesURL) return true;
try {
return provider.matchesURL(url);
} catch {
return false;
}
}
export function hasRegisteredRepositoryProviderCandidate(url: string): boolean {
return pluginRegistry
.getRepositoryProviders()
.some((provider) => repositoryProviderMatchesURL(provider, url));
}
/**
* Treats `matchesURL` as a cheap coarse filter only. Provider ownership is
* established by workspace-scoped structured inspection, so overlapping
* self-hosted URL shapes cannot silently route to registration order.
*/
export async function inspectRegisteredRepositoryURL(context: {
workspaceId: string;
url: string;
signal: AbortSignal;
}): Promise<InspectedRepositoryProvider | null> {
const candidates = pluginRegistry
.getRepositoryProviders()
.filter((provider) => repositoryProviderMatchesURL(provider, context.url));
const inspected = await Promise.allSettled(
candidates.map(async (provider) => ({
provider,
inspection: await provider.inspectURL(context),
})),
);
const matches: InspectedRepositoryProvider[] = inspected.flatMap((result) =>
result.status === "fulfilled" && result.value.inspection
? [{ provider: result.value.provider, inspection: result.value.inspection }]
: [],
);
if (matches.length > 1) {
throw new Error(
`More than one repository provider recognized this URL: ${matches
.map((entry) => entry.provider.id)
.join(", ")}`,
);
}
if (matches[0]) return matches[0];
const failure = inspected.find(
(result): result is PromiseRejectedResult => result.status === "rejected",
);
if (failure) {
throw failure.reason instanceof Error ? failure.reason : new Error(String(failure.reason));
}
return null;
}