/** * In-place HTTP path + Flow name stamps. * * `on()` already registered the trigger (possibly still on the pending-path * sentinel). A wrapper that returned a new trigger would leave `listBindings()` * on the sentinel — mutate the existing object. */ import { isFlow, type AnyFlowDef, type FlowDef } from "./flow.ts"; import { isPendingHttpPath, type HttpPathPending } from "./http-path-pending.ts"; import type { HttpTrigger, Trigger } from "./triggers.ts"; /** * Replace a pending HTTP path on {@link FlowDef} with the file-tree stamp. * * Explicit `http.get("/x")` wins — the pending sentinel is the only path * this function overwrites. Returns the same object with a tighter trigger * type when the original path was pending. * * @param flow - Bound flow (already passed through `on()`) * @param path - Inferred URL (`/notes/:id`) */ export function stampHttpPath( flow: F, path: P, ): StampHttpPath { if (!isFlow(flow)) return flow as StampHttpPath; const apply = (trigger: Trigger): void => { if (trigger.kind !== "http") return; if (!isPendingHttpPath(trigger.path)) return; (trigger as { path: string }).path = path; }; if (flow.$trigger) apply(flow.$trigger); for (const trigger of flow.triggers) apply(trigger); return flow as StampHttpPath; } /** Mutable name fields used by {@link stampFlowName} / {@link on}. */ type FlowNameCarrier = { name: string; unit: string | undefined; }; /** * True when a Flow name is still a placeholder: empty or synthetic `flow_*`. * File-tree / `unit()` may overwrite. * * @param flow - Flow name carrier */ export function isUnsetFlowName(flow: { readonly name: string }): boolean { return !flow.name || flow.name.startsWith("flow_"); } /** * Stamp `unit.export` onto a nameless (or `flow_*`) Flow. * * Explicit `flow("notes.get")` wins. Fills `unit` when missing. * * @param flow - Flow definition * @param name - `notes.get` */ export function stampFlowName(flow: F, name: string): F { if (!isFlow(flow)) return flow; const f = flow as FlowNameCarrier; if (isUnsetFlowName(f)) { f.name = name; } if (!f.unit) { const resolved = f.name || name; const dot = resolved.indexOf("."); f.unit = dot > 0 ? resolved.slice(0, dot) : resolved; } return flow; } /** * Type-level path replacement — only when the bound trigger is still pending. * * @typeParam F - Flow definition * @typeParam P - Stamped path */ export type StampHttpPath = F extends FlowDef ? T extends HttpTrigger ? [Cur] extends [HttpPathPending] ? FlowDef> : F : F : F; export { HTTP_PATH_PENDING, isPendingHttpPath } from "./http-path-pending.ts";