feat: add CI deployment and live progress

This commit is contained in:
2026-09-05 12:09:16 +00:00 Unverified
parent 321f4e807a
commit aa02826dbb
27 changed files with 2711 additions and 180 deletions
+44 -2
View File
@@ -21,8 +21,18 @@ export type RegistryResolveOptions = {
credentials?: RegistryCredentials;
insecure?: boolean;
origin?: string;
cacheTtlMs?: number;
cacheMaxEntries?: number;
clock?: () => number;
};
const DEFAULT_DIGEST_CACHE_TTL_MS = 30_000;
const DEFAULT_DIGEST_CACHE_MAX_ENTRIES = 256;
const digestCache = new Map<
string,
{ digest: Sha256Digest; expiresAt: number }
>();
export type ParsedImageReference = {
registry: string;
repository: string;
@@ -106,6 +116,13 @@ export async function resolveRegistryDigest(
): Promise<Sha256Digest> {
const parsed = parseImageReference(image);
if (parsed.digest) return parsed.digest;
const now = options.clock ?? Date.now;
const cacheTtlMs = Number.isFinite(options.cacheTtlMs)
? Math.max(0, options.cacheTtlMs!)
: DEFAULT_DIGEST_CACHE_TTL_MS;
const cacheMaxEntries = Number.isFinite(options.cacheMaxEntries)
? Math.max(0, Math.floor(options.cacheMaxEntries!))
: DEFAULT_DIGEST_CACHE_MAX_ENTRIES;
const fetcher: RegistryFetch = options.fetch ?? globalThis.fetch;
const scheme = options.insecure ? "http" : "https";
const repository = parsed.repository
@@ -116,6 +133,19 @@ export async function resolveRegistryDigest(
/\/+$/,
"",
);
const credentialsKey = options.credentials
? createHash("sha256")
.update(
`${options.credentials.username}\0${options.credentials.password}`,
)
.digest("hex")
: "anonymous";
const cacheKey = `${origin}\0${parsed.repository}\0${parsed.reference}\0${credentialsKey}`;
const cached = digestCache.get(cacheKey);
if (cached) {
if (cached.expiresAt > now()) return cached.digest;
digestCache.delete(cacheKey);
}
const manifestUrl = `${origin}/v2/${repository}/manifests/${encodeURIComponent(parsed.reference)}`;
const headers = new Headers({ accept: ACCEPT });
if (options.credentials) {
@@ -167,9 +197,21 @@ export async function resolveRegistryDigest(
.get("docker-content-digest")
?.trim()
?.toLowerCase();
let digest: Sha256Digest;
if (advertised !== undefined) {
assertSha256Digest(advertised);
return advertised;
digest = advertised;
} else {
digest = `sha256:${createHash("sha256").update(body).digest("hex")}`;
}
return `sha256:${createHash("sha256").update(body).digest("hex")}`;
if (cacheTtlMs && cacheMaxEntries) {
digestCache.delete(cacheKey);
while (digestCache.size >= cacheMaxEntries)
digestCache.delete(digestCache.keys().next().value!);
digestCache.set(cacheKey, {
digest,
expiresAt: now() + cacheTtlMs,
});
}
return digest;
}