// registry's events. The tool runtime imports this once the broker is bound. // // Emits (novox/hq ADR 0041/0042): // module.registry.image.pushed — a new image (repo:tag) was published to the registry // // This is a genuinely useful signal: a build finished and its image is now pullable, so anything // on the mesh that redeploys, mirrors or announces releases can react without polling the registry // itself. It is discovered by diffing the catalog and each repo's tags — the registry has no push // webhook of its own, so the module watches for it. // // The polling is deliberately unhurried: a new image a minute late is still the event, whereas // hammering the registry's catalog for immediacy nobody asked for is not. import { emit } from "@novox/mesh-sdk/events"; import { RegistryClient } from "./client.js"; const registry = RegistryClient.fromEnv(); // Every repo:tag we have already accounted for. Primed silently on the first look so a registry // that was already full when this started does not announce its whole history as freshly pushed. const seen = new Set(); let primed = false; async function pollCatalog(): Promise { const repos = await registry.listRepositories(); for (const repo of repos) { let tags: string[]; try { tags = await registry.listTags(repo); } catch { continue; // a repo can vanish between catalog and tag read — skip it, catch it next tick } for (const tag of tags) { const id = `${repo}:${tag}`; if (!seen.has(id)) { if (primed) await emit("image.pushed", { repo, tag }); seen.add(id); } } } primed = true; } const tick = (fn: () => Promise, everyMs: number): void => { const run = (): void => void fn().catch((err) => console.error(`[registry] ${err}`)); setInterval(run, everyMs); run(); }; tick(pollCatalog, 60_000); console.log("[registry] watching the catalog for newly pushed images");