/** * InngestModule — provides an Inngest client under the INNGEST token and a * WorkflowService for emitting events. The worker (Track 2b) registers the * matching functions; this module only EMITS (CLAUDE.md #2 — no direct * side-effects from the API). * * Event contract (FIXED — Track 2b consumes these exactly): * "message.received" → { missionId, conversationId, messageId } * "evidence.uploaded" → { missionId, evidenceItemId } */ import { Global, Inject, Injectable, Module } from "@nestjs/common"; import { Inngest } from "inngest"; export const INNGEST = Symbol("INNGEST"); /** WorkflowService is the only surface that sends Inngest events from the API. */ @Injectable() export class WorkflowService { constructor(@Inject(INNGEST) private readonly inngest: Inngest) {} async send( name: | "message.received" | "evidence.uploaded" | "mission.route_plan_requested" | "mission.facts_confirmed" | "action.execute_requested" | "action.executed" | "action.failed" | "mission.followup_due" | "email.reply_received" | "mission.reply_processed" | "mission.resolution_claimed" | "ledger.outcome_recorded" | "swarm.entity_resolution_requested" | "swarm.member_joined" | "portal.assist_requested" | "portal.assist_proceeded" | "case.lookup_requested", data: Record, ): Promise { try { await this.inngest.send({ name, data }); } catch (err) { // REVIEW_FINDINGS F1: event bus must not crash user-facing API requests. // Non-blocking: log and continue. Loop-critical events (route_plan, // execute, facts_confirmed) will be retried by the caller or surfaced // through the snapshot. A transactional outbox is the Phase-2 fix. console.error(`[WorkflowService] Failed to send event "${name}":`, err); } } } function createInngestClient(): Inngest { // In dev mode (INNGEST_DEV=1) the SDK automatically targets the local Inngest // dev server. Set INNGEST_BASE_URL to override (e.g. "http://localhost:8288"). return new Inngest({ id: "courtmitra" }); } @Global() @Module({ providers: [ { provide: INNGEST, useFactory: (): Inngest => createInngestClient(), }, WorkflowService, ], exports: [INNGEST, WorkflowService], }) export class InngestModule {}