import { inject, injectable } from "@codemation/core"; import type { Hono } from "hono"; import type { Item } from "@codemation/core"; import type { DispatchItemMeta, WorkflowDispatch } from "@codemation/core/contracts"; import { ApplicationTokens } from "../applicationTokens"; import { InternalHmacAuthMiddleware } from "../pairing/InternalHmacAuthMiddleware"; import { RunHttpRouteHandler } from "../presentation/http/routeHandlers/RunHttpRouteHandler"; import type { InternalHonoApiRouteRegistrar } from "../presentation/http/hono/InternalHonoApiRouteRegistrar"; import { BoundedDedupMap } from "./BoundedDedupMap"; @injectable() export class TriggerDispatchRegistrar implements InternalHonoApiRouteRegistrar { constructor( @inject(InternalHmacAuthMiddleware) private readonly hmacMiddleware: InternalHmacAuthMiddleware, @inject(RunHttpRouteHandler) private readonly runHttpRouteHandler: RunHttpRouteHandler, @inject(ApplicationTokens.TriggerDispatchDedupMap) private readonly dedup: BoundedDedupMap, ) {} register(app: Hono): void { app.post("/internal/dispatch", this.hmacMiddleware.handle(), async (c) => { const rawBody = c.get("body" as never) as string | undefined; const body = (rawBody ? JSON.parse(rawBody) : await c.req.json()) as Partial; if (!body.workflowId || typeof body.workflowId !== "string") { return c.json({ error: "workflowId is required" }, 400); } const dispatchItems = Array.isArray(body.items) ? (body.items as DispatchItemMeta[]) : []; const dedupedItems = dispatchItems.filter((item) => !this.dedup.hasSeen(`${body.workflowId}:${item.id}`)); if (dispatchItems.length > 0 && dedupedItems.length === 0) { return c.json({ deduplicated: true }, 200); } const createRequest = { workflowId: body.workflowId, ...(body.triggerNodeId ? { startAt: body.triggerNodeId } : {}), ...(dedupedItems.length > 0 ? { items: dedupedItems.map((m) => this.toRunItem(m)) } : {}), }; const acceptsSse = (c.req.header("accept") ?? "").includes("text/event-stream"); return this.runHttpRouteHandler.runOrStream(createRequest, acceptsSse); }); } private toRunItem(meta: DispatchItemMeta): Item { return { json: meta.json ?? {}, ...(meta.binary ? { binary: meta.binary } : {}), }; } }