{"version":3,"file":"middleware.cjs","names":[],"sources":["../../../src/components/middleware/middleware.ts"],"sourcesContent":["import type { Jsonify } from \"../../helpers/jsonify.ts\";\nimport type { MaybePromise } from \"../../helpers/types.ts\";\nimport type {\n  Context,\n  EventPayload,\n  JsonError,\n  SendEventBaseOutput,\n  StepOptions,\n} from \"../../types.ts\";\nimport type { Inngest } from \"../Inngest.ts\";\nimport type { InngestFunction } from \"../InngestFunction.ts\";\nimport type { createStepTools } from \"../InngestStepTools.ts\";\nimport type { OpenStringUnion } from \"./types.ts\";\n\n/**\n * Namespace containing middleware-related types and base class.\n */\nexport namespace Middleware {\n  /**\n   * Base interface for output transformers. Extend this and override `Out` to\n   * create custom transformers. This is necessary because TypeScript doesn't\n   * support higher-kinded types.\n   *\n   * @example\n   * ```ts\n   * interface BooleanToStringTransform extends Middleware.StaticTransform {\n   *   Out: this[\"In\"] extends boolean ? string : this[\"In\"];\n   * }\n   * ```\n   */\n  export type StaticTransform = {\n    In: unknown;\n    Out: unknown;\n  };\n\n  /**\n   * Default transform. Applies the same transform as `JSON.stringify`.\n   */\n  export interface DefaultStaticTransform extends StaticTransform {\n    Out: Jsonify<this[\"In\"]>;\n  }\n\n  /**\n   * The step tools available to middleware for extending step functionality.\n   * This is the same type as `step` in the function handler context.\n   */\n  export type StepTools = ReturnType<typeof createStepTools<Inngest.Any>>;\n\n  /**\n   * The argument passed to `transformSendEvent`.\n   */\n  export type TransformSendEventArgs = {\n    events: EventPayload<Record<string, unknown>>[];\n    readonly fn: DeepReadonly<InngestFunction.Any> | null;\n  };\n\n  /**\n   * The argument passed to `transformStepInput`.\n   */\n  export type TransformStepInputArgs = {\n    readonly fn: DeepReadonly<InngestFunction.Any>;\n    readonly stepInfo: Readonly<\n      Pick<StepInfo, \"hashedId\" | \"memoized\" | \"stepType\">\n    >;\n    stepOptions: StepOptions;\n    input: unknown[];\n  };\n\n  /** The argument passed to `wrapStepHandler`. */\n  export type WrapStepHandlerArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    next: () => Promise<unknown>;\n    stepInfo: StepInfo;\n  }>;\n\n  /**\n   * A single memoized step entry received in `transformFunctionInput`.\n   */\n  type MemoizedStep =\n    | { type: \"data\"; data: unknown }\n    | { type: \"error\"; error: JsonError }\n    | { type: \"input\"; input: unknown };\n\n  /**\n   * Memoized step state keyed by hashed step ID.\n   */\n  type MemoizedSteps = Record<string, MemoizedStep>;\n\n  /**\n   * The argument passed to `transformFunctionInput`.\n   */\n  export type TransformFunctionInputArgs = {\n    ctx: Context.Any;\n    readonly fn: DeepReadonly<InngestFunction.Any>;\n    steps: MemoizedSteps;\n  };\n\n  /**\n   * The argument passed to the static `onRegister` hook.\n   */\n  export type OnRegisterArgs = Readonly<{\n    client: Inngest.Any;\n    fn: InngestFunction.Any | null;\n  }>;\n\n  /**\n   * Information about the incoming HTTP request that triggered this execution.\n   */\n  export type Request = {\n    body: () => Promise<unknown>;\n    headers: Readonly<Record<string, string>>;\n    method: string;\n    url: URL;\n  };\n\n  /** The argument passed to `wrapFunctionHandler`. */\n  export type WrapFunctionHandlerArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    next: () => Promise<unknown>;\n  }>;\n\n  /** The argument passed to `wrapRequest`. */\n  export type WrapRequestArgs = DeepReadonly<{\n    fn: InngestFunction.Any | null;\n    next: () => Promise<Response>;\n    requestArgs: readonly unknown[];\n    requestInfo: Request;\n    runId: string;\n  }>;\n\n  /** The argument passed to `wrapSendEvent`. */\n  export type WrapSendEventArgs = DeepReadonly<{\n    events: EventPayload<Record<string, unknown>>[];\n    fn: InngestFunction.Any | null;\n    next: () => Promise<SendEventBaseOutput>;\n  }>;\n\n  /** The argument passed to `wrapStep`. */\n  export type WrapStepArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    next: () => Promise<unknown>;\n    stepInfo: StepInfo;\n  }>;\n\n  /**\n   * The shape of the HTTP response returned by the middleware chain.\n   * This is what `next()` resolves with inside `wrapRequest`.\n   */\n  export type Response = {\n    body: string;\n    headers: Record<string, string>;\n    status: number;\n  };\n\n  /**\n   * The argument passed to `onMemoizationEnd`.\n   */\n  export type OnMemoizationEndArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n  }>;\n\n  /**\n   * The argument passed to `onStepStart`.\n   */\n  export type OnStepStartArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    stepInfo: StepInfo;\n  }>;\n\n  /**\n   * The argument passed to `onStepError`.\n   */\n  export type OnStepErrorArgs = DeepReadonly<{\n    ctx: Context.Any;\n    error: Error;\n    fn: InngestFunction.Any;\n\n    /**\n     * Whether this is the final attempt for the step, meaning retries are\n     * exhausted or the error is non-retriable. When `false`, the step will be\n     * retried.\n     */\n    isFinalAttempt: boolean;\n\n    stepInfo: StepInfo;\n  }>;\n\n  /**\n   * The argument passed to `onStepComplete`.\n   */\n  export type OnStepCompleteArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    output: unknown;\n    stepInfo: StepInfo;\n  }>;\n\n  /**\n   * The argument passed to `onRunStart`.\n   */\n  export type OnRunStartArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n  }>;\n\n  /**\n   * The argument passed to `onRunComplete`.\n   */\n  export type OnRunCompleteArgs = DeepReadonly<{\n    ctx: Context.Any;\n    fn: InngestFunction.Any;\n    output: unknown;\n  }>;\n\n  /**\n   * The argument passed to `onRunError`.\n   */\n  export type OnRunErrorArgs = DeepReadonly<{\n    ctx: Context.Any;\n    error: Error;\n    fn: InngestFunction.Any;\n\n    /**\n     * Whether this is the final attempt for the function, meaning retries are\n     * exhausted or the error is non-retriable. When `false`, the function will\n     * be retried.\n     */\n    isFinalAttempt: boolean;\n  }>;\n\n  /**\n   * The type of step. This union may be extended in the future, and will not be\n   * considered a breaking change.\n   */\n  export type StepType = OpenStringUnion<\n    | \"ai.infer\"\n    | \"ai.wrap\"\n    | \"fetch\"\n    | \"group.experiment\"\n    | \"invoke\"\n    | \"realtime.publish\"\n    | \"run\"\n    | \"sendEvent\"\n    | \"sleep\"\n    | \"waitForEvent\"\n    | \"waitForSignal\"\n  >;\n\n  export type StepInfo = {\n    /**\n     * Unique ID for the step. This is a hash of the user-defined step ID,\n     * including the implicit index if the user-defined ID is not unique.\n     */\n    hashedId: string;\n\n    /**\n     * The arguments passed to the step function, if any. For `step.run()`,\n     * these are the arguments after the id and handler function.\n     */\n    input?: unknown[];\n\n    /**\n     * Whether the step result is being retrieved from memoized state (true)\n     * or being executed fresh (false).\n     */\n    memoized: boolean;\n\n    /**\n     * Based on the first argument passed to the `step` method.\n     */\n    options: StepOptions;\n\n    stepType: StepType;\n  };\n\n  /**\n   * Base class for creating middleware. Extend this class to create custom\n   * middleware with hooks for step execution.\n   */\n  // @privateRemark\n  // Methods are nullish instead of noops as a performance optimization. This is\n  // primarily because of `wrapStep`. Each defined `wrapStep` method adds 1 more\n  // promise to the chain for each step. This chain runs every time the step\n  // completes/errors (even when memoized).\n  export abstract class BaseMiddleware {\n    readonly client: Inngest.Any;\n\n    /**\n     * Used to identify the middleware instance in logs. Uniqueness is not\n     * required, though using multiple middleware with the same ID in the same\n     * app may cause confusion when debugging.\n     */\n    abstract readonly id: string;\n\n    /**\n     * Declare this to statically specify how function return types are\n     * transformed. By default, the function return type is Jsonified.\n     *\n     * Must match the same structure as `StaticTransform` to imitate\n     * higher-kinded types.\n     *\n     * @example\n     * ```ts\n     * interface PreserveDate extends Middleware.StaticTransform {\n     *   Out: this[\"In\"] extends Date ? Date : Jsonify<this[\"In\"]>;\n     * }\n     *\n     * class MyMiddleware extends Middleware.BaseMiddleware {\n     *   declare functionOutputTransform: PreserveDate;\n     * }\n     * ```\n     *\n     * @default Middleware.DefaultStaticTransform (e.g. Date -> string)\n     */\n    declare functionOutputTransform: DefaultStaticTransform;\n\n    /**\n     * Declare this to statically specify how step output types are transformed.\n     * By default, the step output type is Jsonified.\n     *\n     * Must match the same structure as `StaticTransform` to imitate\n     * higher-kinded types.\n     *\n     * @example\n     * ```ts\n     * interface PreserveDate extends Middleware.StaticTransform {\n     *   Out: this[\"In\"] extends Date ? Date : Jsonify<this[\"In\"]>;\n     * }\n     *\n     * class MyMiddleware extends Middleware.BaseMiddleware {\n     *   declare stepOutputTransform: PreserveDate;\n     * }\n     * ```\n     *\n     * @default Middleware.DefaultStaticTransform (e.g. Date -> string)\n     */\n    declare stepOutputTransform: DefaultStaticTransform;\n\n    constructor({ client }: { client: Inngest.Any }) {\n      this.client = client;\n    }\n\n    /**\n     * Called when the middleware class is added to an Inngest client or Inngest\n     * function. Use this for one-time setup that needs a reference to the\n     * client instance (e.g. registering processors, setting feature flags).\n     *\n     * Do not mutate arguments.\n     */\n    static onRegister?(args: Middleware.OnRegisterArgs): void;\n\n    /**\n     * Called 1 time per request, after memoization completes.\n     *\n     * If all memoized steps have been resolved/rejected, then this hook calls.\n     * This is at the top of the function handler when there are 0 memoized\n     * steps.\n     *\n     * If a new step is found before resolving/rejecting all memoized steps,\n     * then this calls.\n     *\n     * Do not mutate arguments.\n     */\n    onMemoizationEnd?(arg: Middleware.OnMemoizationEndArgs): MaybePromise<void>;\n\n    /**\n     * Called when the run completes successfully. Does NOT call when the run\n     * errors: `onRunError` calls instead.\n     *\n     * Do not mutate arguments.\n     */\n    onRunComplete?(arg: Middleware.OnRunCompleteArgs): MaybePromise<void>;\n\n    /**\n     * Called when the function throws an error.\n     *\n     * Do not mutate arguments.\n     */\n    onRunError?(arg: Middleware.OnRunErrorArgs): MaybePromise<void>;\n\n    /**\n     * Called 1 time per run on the very first request (0 memoized steps,\n     * attempt 0). Does NOT call on subsequent requests where steps are being\n     * replayed.\n     *\n     * Do not mutate arguments.\n     */\n    onRunStart?(arg: Middleware.OnRunStartArgs): MaybePromise<void>;\n\n    /**\n     * Called when a step successfully completes. Only called for `step.run`\n     * and `step.sendEvent`. Never called for memoized step outputs. Does NOT\n     * call when the step errors: `onStepError` calls instead.\n     *\n     * Do not mutate arguments.\n     */\n    onStepComplete?(arg: Middleware.OnStepCompleteArgs): MaybePromise<void>;\n\n    /**\n     * Called each time a step errors. Only called for `step.run` and\n     * `step.sendEvent`. Never called for memoized errors.\n     *\n     * Do not mutate arguments.\n     */\n    onStepError?(arg: Middleware.OnStepErrorArgs): MaybePromise<void>;\n\n    /**\n     * Called 1 time per step before running its handler. Only called for\n     * `step.run` and `step.sendEvent`.\n     *\n     * Do not mutate arguments.\n     */\n    onStepStart?(arg: Middleware.OnStepStartArgs): MaybePromise<void>;\n\n    /**\n     * Called 1 time per request (likely multiple times per run). Return the\n     * (potentially modified) arg object.\n     *\n     * Use cases:\n     * - Dependency injection.\n     * - Deserialize events before passing it to the function handler.\n     *\n     * Do not mutate arguments.\n     */\n    // @privateRemark\n    // This hook exists because `wrapFunctionHandler` can't be used for the\n    // transformation's static type inference. For example, if the user added\n    // `ctx.db` in `wrapFunctionHandler` then the static types wouldn't show\n    // `ctx.db` in the function handler.\n    transformFunctionInput?(\n      arg: Middleware.TransformFunctionInputArgs,\n    ): MaybePromise<Middleware.TransformFunctionInputArgs>;\n\n    /**\n     * Called when sending events. This is either `step.sendEvent` or\n     * `client.send`. Return the (potentially modified) arg object.\n     *\n     * Use cases:\n     * - Serialize event data before sending it to the Inngest Server.\n     *\n     * Do not mutate arguments.\n     */\n    transformSendEvent?(\n      arg: Middleware.TransformSendEventArgs,\n    ): MaybePromise<Middleware.TransformSendEventArgs>;\n\n    /**\n     * Called 1 time per step per request (likely multiple times per step).\n     * Return the (potentially modified) arg object.\n     *\n     * Use cases:\n     * - Modify step options (e.g. the step ID).\n     * - Modify step input args.\n     *\n     * Do not mutate arguments.\n     */\n    // @privateRemark\n    // Step input transformation could happen in `wrapStep`, but we chose not to\n    // for the following reasons:\n    // 1. `wrapStep` may have a negative performance impact under certain\n    //    workloads.\n    // 2. `wrapStep` is a little more complicated to use.\n    // 3. Since `transformFunctionInput` must exist, having this hook\n    //    establishes a consistent pattern for input transformation.\n    transformStepInput?(\n      arg: TransformStepInputArgs,\n    ): MaybePromise<TransformStepInputArgs>;\n\n    /**\n     * Called 1 time per request.\n     *\n     * Use cases:\n     * - AsyncLocalStorage context.\n     * - Function-level output/error transformation.\n     * - Prepend/append steps around the function handler.\n     *\n     * Must call `next()` to continue processing. Do not mutate arguments.\n     *\n     * **Important:** `next()` only resolves when the function completes. On\n     * requests where a fresh step is discovered, control flow is interrupted\n     * and `next()` never resolves.\n     */\n    wrapFunctionHandler?(args: WrapFunctionHandlerArgs): Promise<unknown>;\n\n    /**\n     * Called 1 time per request.\n     *\n     * Use cases:\n     * - Custom auth.\n     * - Expose request data to the Inngest function handler.\n     * - Metrics.\n     *\n     * Must call `next()` to continue processing. Do not mutate arguments.\n     */\n    wrapRequest?(args: WrapRequestArgs): Promise<Response>;\n\n    /**\n     * Called each time events are sent (either `client.send` or\n     * `step.sendEvent`).\n     *\n     * Use cases:\n     * - Backup events (e.g. blob store) when they fail to send.\n     * - Metrics.\n     *\n     * Must call `next()` to continue processing. Do not mutate arguments.\n     */\n    wrapSendEvent?(args: WrapSendEventArgs): Promise<SendEventBaseOutput>;\n\n    /**\n     * Called 1 time per step per request. Called for all step kinds. Depending\n     * on your use case, you may want `wrapStepHandler` instead.\n     *\n     * Use cases:\n     * - Deserialize step output before returning it to the function handler.\n     * - Handle step failure errors (after exhausting retries).\n     * - Prepend/append steps around a step.\n     *\n     * Must call `next()` to continue processing. Do not mutate arguments.\n     *\n     * NOTE: `next()` only resolves when the step completes/fails. On requests\n     * where a fresh step is discovered, control flow is interrupted and\n     * `next()` never resolves.\n     */\n    wrapStep?(args: WrapStepArgs): Promise<unknown>;\n\n    /**\n     * Called 1 time per step attempt. Wraps the step's handler. Only called for\n     * `step.run` and `step.sendEvent`. Use this to modify the handler's\n     * returned output or thrown error before it's sent to the Inngest Server.\n     *\n     * Use cases:\n     * - Serialize step output before sending it to the Inngest Server.\n     * - Handle step attempt errors (before exhausting retries).\n     *\n     * Must call `next()` to continue processing. Do not mutate arguments.\n     */\n    // @privateRemark\n    // This hook exists because of checkpointing. For serialization middleware\n    // to work with checkpointing, we need to both:\n    // 1. Serialize the step output before sending it to the Inngest Server.\n    // 2. Deserialize the step output before returning it to the function handler.\n    //\n    // We initially solved this by calling `wrapStep` twice per step per\n    // request. But this breaks the \"prepend with step\" logic since we'd\n    // encounter the prepended step twice; this caused us to run the prepended\n    // step twice.\n    //\n    // Now that we have `wrapStepHandler`, it can be responsible for\n    // serialization and `wrapStep` can be responsible for deserialization.\n    wrapStepHandler?(args: WrapStepHandlerArgs): Promise<unknown>;\n  }\n\n  /**\n   * A no-arg constructor for a BaseMiddleware subclass. Used in client and\n   * function options so that fresh instances are created per-request.\n   */\n  export type Class = (new (args: {\n    client: Inngest.Any;\n  }) => BaseMiddleware) & {\n    // Static methods aren't captured by `new () => ...`, so we repeat it here.\n    onRegister?(arg: OnRegisterArgs): void;\n  };\n}\n\ntype DeepReadonly<T> = T extends (infer U)[]\n  ? readonly DeepReadonly<U>[]\n  : // Do not make functions readonly, since that leads to weird stuff like not\n    // being able to call `.catch()` on the returned promise.\n    T extends Function\n    ? T\n    : // Do not recurse into these types. If that happens, then the resulting\n      // type will not be compatible with the original type\n      T extends Date | RegExp | Error | Map<unknown, unknown> | Set<unknown>\n      ? Readonly<T>\n      : T extends object\n        ? { readonly [K in keyof T]: DeepReadonly<T[K]> }\n        : T;\n"],"mappings":";;;;CAiSS,MAAe,eAAe;EACnC,AAAS;EAqDT,YAAY,EAAE,UAAmC;AAC/C,QAAK,SAAS"}