import type { AppEnv } from "@autumn/shared"; import { JobName } from "./JobName.js"; import { addTaskToQueue, runHatchetWorkflow } from "./queueUtils.js"; // ============ Payload Types ============ export type SendProductsUpdatedPayload = { orgId: string; env: AppEnv; customerId: string; customerProductId: string; scenario: string; }; type GenerateFeatureDisplayPayload = { featureId: string; orgId: string; env: AppEnv; }; type VerifyCacheConsistencyPayload = { customerId: string; orgId: string; env: AppEnv; source: string; newCustomerProductId: string; previousFullCustomer: string; }; export type GrantCheckoutRewardPayload = { orgId: string; env: AppEnv; customerId: string; productId: string; stripeSubscriptionId?: string; }; export type BatchResetCusEntsPayload = { orgId: string; env: string; resets: { internalCustomerId: string; customerId: string; cusEntIds: string[]; }[]; }; export type StoreInvoiceLineItemsPayload = { orgId: string; env: AppEnv; stripeInvoiceId: string; autumnInvoiceId: string; /** LineItem[] for matching Stripe line items back to Autumn billing context */ billingLineItems?: unknown[]; }; // ============ Workflow Registry ============ type WorkflowRunner = "sqs" | "hatchet"; type WorkflowConfig = { jobName: JobName; runner: WorkflowRunner; _payloadType?: TPayload; }; const workflowRegistry = { sendProductsUpdated: { jobName: JobName.SendProductsUpdated, runner: "sqs", } as WorkflowConfig, generateFeatureDisplay: { jobName: JobName.GenerateFeatureDisplay, runner: "sqs", } as WorkflowConfig, verifyCacheConsistency: { jobName: JobName.VerifyCacheConsistency, runner: "hatchet", } as WorkflowConfig, grantCheckoutReward: { jobName: JobName.GrantCheckoutReward, runner: "sqs", } as WorkflowConfig, batchResetCusEnts: { jobName: JobName.BatchResetCusEnts, runner: "sqs", } as WorkflowConfig, storeInvoiceLineItems: { jobName: JobName.StoreInvoiceLineItems, runner: "sqs", } as WorkflowConfig, } as const; // ============ Type Utilities ============ type WorkflowRegistry = typeof workflowRegistry; type WorkflowName = keyof WorkflowRegistry; type PayloadFor = WorkflowRegistry[T] extends WorkflowConfig ? P : never; type TriggerOptions = { delayMs?: number; metadata?: Record; }; // ============ Generic Trigger Function (internal) ============ const triggerWorkflow = async ({ name, payload, options, }: { name: T; payload: PayloadFor; options?: TriggerOptions; }) => { const config = workflowRegistry[name]; if (config.runner === "hatchet") { await runHatchetWorkflow({ workflowName: config.jobName as JobName.VerifyCacheConsistency, payload: payload as VerifyCacheConsistencyPayload, delayMs: options?.delayMs, metadata: options?.metadata, }); } else { await addTaskToQueue({ jobName: config.jobName, payload: payload, delayMs: options?.delayMs, }); } }; // ============ Typed Trigger Functions (exported) ============ export const workflows = { triggerSendProductsUpdated: ( payload: SendProductsUpdatedPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "sendProductsUpdated", payload, options }), triggerGenerateFeatureDisplay: ( payload: GenerateFeatureDisplayPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "generateFeatureDisplay", payload, options }), triggerVerifyCacheConsistency: ( payload: VerifyCacheConsistencyPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "verifyCacheConsistency", payload, options }), triggerGrantCheckoutReward: ( payload: GrantCheckoutRewardPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "grantCheckoutReward", payload, options }), triggerBatchResetCusEnts: ( payload: BatchResetCusEntsPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "batchResetCusEnts", payload, options }), triggerStoreInvoiceLineItems: ( payload: StoreInvoiceLineItemsPayload, options?: TriggerOptions, ) => triggerWorkflow({ name: "storeInvoiceLineItems", payload, options }), };