import { browser } from "$app/env";
import { untrack } from "svelte";
import { fetchCommitStatuses, type CommitStatuses } from "#lib/api/commitStatuses.ts";
import { pollPipelineCollection } from "#lib/components/repo/pipelines/livePipelines.ts";
import type { RepoInfo } from "#lib/components/repo/types.ts";
interface CommitStatusTarget {
repo: RepoInfo;
shas: string[];
}
const replaceStatuses = (current: CommitStatuses, updated: CommitStatuses) => {
for (const sha of Object.keys(current)) {
if (!(sha in updated)) delete current[sha];
}
Object.assign(current, updated);
};
export const liveCommitStatuses = (
target: () => Promise<CommitStatusTarget>
): Promise<CommitStatuses> => {
if (!browser) return Promise.resolve({});
const current = $state<CommitStatuses>({});
$effect(() => {
const pendingTarget = target();
let stopped = false;
let stopPolling = () => {};
untrack(() => replaceStatuses(current, {}));
void pendingTarget
.then(async (resolved) => {
if (!resolved.repo.spindle || resolved.shas.length === 0) return;
const initial = await fetchCommitStatuses(
resolved.repo.ownerHandle,
resolved.repo.name,
resolved.shas
);
if (stopped) return;
replaceStatuses(current, initial);
stopPolling = pollPipelineCollection(
Object.values(initial),
async (_pipelines, signal) =>
Object.values(
await fetchCommitStatuses(
resolved.repo.ownerHandle,
resolved.repo.name,
resolved.shas,
signal
)
),
(updated) =>
replaceStatuses(
current,
Object.fromEntries(updated.map((pipeline) => [pipeline.sha, pipeline]))
)
);
})
.catch(() => {});
return () => {
stopped = true;
stopPolling();
};
});
return Promise.resolve(current);
};