~james/core

core/web/src/lib/api/liveCommitStatuses.svelte.ts -rw-r--r-- 1.8 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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);
};