/** * 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", data: Record, ): Promise { await this.inngest.send({ name, data }); } } 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 {}