{"version":3,"file":"InngestFunction.cjs","names":["queryKeys","fn: FunctionConfig","eventName: string","ret: NonNullable<FunctionConfig[\"cancel\"]>[number]","timeStr","config: FunctionConfig[]","internalEvents","triggers: FunctionConfig[\"triggers\"]","EventType","createExecutionEngine","defaultCheckpointingOptions"],"sources":["../../src/components/InngestFunction.ts"],"sourcesContent":["import { internalEvents, queryKeys } from \"../helpers/consts.ts\";\nimport { timeStr } from \"../helpers/strings.ts\";\nimport type { RecursiveTuple, StrictUnion } from \"../helpers/types.ts\";\nimport {\n  type Cancellation,\n  type CheckpointingOptions,\n  type ConcurrencyOption,\n  type DefaultMaxRuntime,\n  defaultCheckpointingOptions,\n  type FunctionConfig,\n  type Handler,\n  type InternalCheckpointingOptions,\n  type TimeStr,\n  type TimeStrBatch,\n} from \"../types.ts\";\nimport { createExecutionEngine } from \"./execution/engine.ts\";\nimport type {\n  IInngestExecution,\n  InngestExecutionOptions,\n} from \"./execution/InngestExecution.ts\";\n\nimport type { Inngest } from \"./Inngest.ts\";\nimport type { Middleware } from \"./middleware/middleware.ts\";\nimport { EventType, type EventTypeWithAnySchema } from \"./triggers/triggers.ts\";\n\n/**\n * A stateless Inngest function, wrapping up function configuration and any\n * in-memory steps to run when triggered.\n *\n * This function can be \"registered\" to create a handler that Inngest can\n * trigger remotely.\n *\n * @public\n */\nexport class InngestFunction<\n  TFnOpts extends InngestFunction.Options<TTriggers, TFailureHandler>,\n  THandler extends Handler.Any,\n  TFailureHandler extends Handler.Any,\n  TClient extends Inngest.Any = Inngest.Any,\n  TTriggers extends\n    InngestFunction.Trigger<string>[] = InngestFunction.Trigger<string>[],\n> implements InngestFunction.Like\n{\n  static stepId = \"step\";\n  static failureSuffix = \"-failure\";\n\n  get [Symbol.toStringTag](): typeof InngestFunction.Tag {\n    return InngestFunction.Tag;\n  }\n\n  public readonly opts: TFnOpts;\n  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: used internally\n  private readonly fn: THandler;\n  private readonly onFailureFn?: TFailureHandler;\n  protected readonly client: TClient;\n\n  /**\n   * A stateless Inngest function, wrapping up function configuration and any\n   * in-memory steps to run when triggered.\n   *\n   * This function can be \"registered\" to create a handler that Inngest can\n   * trigger remotely.\n   */\n  constructor(\n    client: TClient,\n\n    /**\n     * Options\n     */\n    opts: TFnOpts,\n    fn: THandler,\n  ) {\n    this.client = client;\n    this.opts = opts;\n    this.fn = fn;\n    this.onFailureFn = this.opts.onFailure;\n  }\n\n  /**\n   * The generated or given ID for this function.\n   */\n  public id(prefix?: string): string {\n    return [prefix, this.opts.id].filter(Boolean).join(\"-\");\n  }\n\n  /**\n   * The generated or given ID for this function, prefixed with the app ID. This\n   * is used for routing invokes and identifying the function across apps.\n   */\n  protected get absoluteId(): string {\n    return this.id(this.client.id);\n  }\n\n  /**\n   * The name of this function as it will appear in the Inngest Cloud UI.\n   */\n  public get name(): string {\n    return this.opts.name || this.id();\n  }\n\n  /**\n   * The description of this function.\n   */\n  public get description(): string | undefined {\n    return this.opts.description;\n  }\n\n  /**\n   * Retrieve the Inngest config for this function.\n   */\n\n  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: used within the SDK\n  private getConfig({\n    baseUrl,\n    appPrefix,\n    isConnect,\n  }: {\n    /**\n     * Must be provided a URL that will be used to access the function and step.\n     * This function can't be expected to know how it will be accessed, so\n     * relies on an outside method providing context.\n     */\n    baseUrl: URL;\n\n    /**\n     * The prefix for the app that this function is part of.\n     */\n    appPrefix: string;\n\n    /**\n     * Whether this function is being used in a Connect handler.\n     */\n    isConnect?: boolean;\n  }): FunctionConfig[] {\n    const fnId = this.id(appPrefix);\n    const stepUrl = new URL(baseUrl.href);\n    stepUrl.searchParams.set(queryKeys.FnId, fnId);\n    stepUrl.searchParams.set(queryKeys.StepId, InngestFunction.stepId);\n\n    const {\n      retries: attempts,\n      cancelOn,\n      idempotency,\n      batchEvents,\n      rateLimit,\n      throttle,\n      concurrency,\n      debounce,\n      timeouts,\n      priority,\n      singleton,\n    } = this.opts;\n\n    /**\n     * Convert retries into the format required when defining function\n     * configuration.\n     */\n    const retries = typeof attempts === \"undefined\" ? undefined : { attempts };\n\n    const triggers = this.getConfigTriggers(fnId);\n\n    const fn: FunctionConfig = {\n      id: fnId,\n      name: this.name,\n      triggers,\n      steps: {\n        [InngestFunction.stepId]: {\n          id: InngestFunction.stepId,\n          name: InngestFunction.stepId,\n          runtime: {\n            type: isConnect ? \"ws\" : \"http\",\n            url: stepUrl.href,\n          },\n          retries,\n        },\n      },\n      idempotency,\n      batchEvents,\n      rateLimit,\n      throttle,\n      concurrency,\n      debounce,\n      priority,\n      timeouts,\n      singleton,\n    };\n\n    if (cancelOn) {\n      fn.cancel = cancelOn.map(({ event, timeout, if: ifStr, match }) => {\n        let eventName: string;\n        if (typeof event === \"string\") {\n          eventName = event;\n        } else {\n          eventName = event.name;\n        }\n\n        const ret: NonNullable<FunctionConfig[\"cancel\"]>[number] = {\n          event: eventName,\n        };\n\n        if (timeout) {\n          ret.timeout = timeStr(timeout);\n        }\n\n        if (match) {\n          ret.if = `event.${match} == async.${match}`;\n        } else if (ifStr) {\n          ret.if = ifStr;\n        }\n\n        return ret;\n      }, []);\n    }\n\n    const config: FunctionConfig[] = [fn];\n\n    if (this.onFailureFn) {\n      const id = `${fn.id}${InngestFunction.failureSuffix}`;\n      const name = `${fn.name ?? fn.id} (failure)`;\n\n      const failureStepUrl = new URL(stepUrl.href);\n      failureStepUrl.searchParams.set(queryKeys.FnId, id);\n\n      config.push({\n        id,\n        name,\n        triggers: [\n          {\n            event: internalEvents.FunctionFailed,\n            expression: `event.data.function_id == '${fnId}'`,\n          },\n        ],\n        steps: {\n          [InngestFunction.stepId]: {\n            id: InngestFunction.stepId,\n            name: InngestFunction.stepId,\n            runtime: {\n              type: \"http\",\n              url: failureStepUrl.href,\n            },\n            retries: { attempts: 1 },\n          },\n        },\n      });\n    }\n\n    return config;\n  }\n\n  /**\n   * Build the trigger list for this function's `getConfig` payload. Subclasses\n   * (e.g. `DeferredFunction`) override this to emit implicit triggers.\n   */\n  protected getConfigTriggers(_fnId: string): FunctionConfig[\"triggers\"] {\n    const triggers: FunctionConfig[\"triggers\"] = [];\n\n    for (const trigger of this.opts.triggers ?? []) {\n      if (trigger.cron) {\n        const cronTrigger = trigger as { cron: string; jitter?: string };\n        triggers.push({\n          cron: cronTrigger.cron,\n          ...(cronTrigger.jitter ? { jitter: cronTrigger.jitter } : {}),\n        });\n        continue;\n      }\n\n      if (!trigger.event) {\n        continue;\n      }\n\n      // The invoke event is in the triggers if they used the `invoke` trigger\n      // helper. But we need to remove it in the config, or else the function\n      // will be triggered by any invoke.\n      let eventName = trigger.event;\n      if (eventName instanceof EventType) {\n        eventName = eventName.name;\n      }\n      if (eventName === internalEvents.FunctionInvoked) {\n        continue;\n      }\n\n      triggers.push({ event: eventName, expression: trigger.if });\n    }\n\n    return triggers;\n  }\n\n  protected createExecution(opts: CreateExecutionOptions): IInngestExecution {\n    const options: InngestExecutionOptions = {\n      fn: this,\n      ...opts.partialOptions,\n    };\n\n    return createExecutionEngine(options);\n  }\n\n  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: used within the SDK\n  private shouldOptimizeParallelism(): boolean {\n    // TODO We should check the commhandler's client instead of this one?\n    return (\n      this.opts.optimizeParallelism ??\n      this.client[\"options\"].optimizeParallelism ??\n      true\n    );\n  }\n\n  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: used within the SDK\n  private shouldAsyncCheckpoint(\n    requestedRunStep: string | undefined,\n    internalFnId: string | undefined,\n    disableImmediateExecution: boolean,\n    defaultMaxRuntime: DefaultMaxRuntime,\n  ): InternalCheckpointingOptions | undefined {\n    if (requestedRunStep || !internalFnId || disableImmediateExecution) {\n      return;\n    }\n\n    // TODO We should check the commhandler's client instead of this one?\n    const userCfg =\n      this.opts.checkpointing ??\n      this.client[\"options\"].checkpointing ??\n      this.opts.experimentalCheckpointing ??\n      this.client[\"options\"].experimentalCheckpointing ??\n      true;\n\n    if (!userCfg) {\n      // Opted out\n      return;\n    }\n\n    if (userCfg === true) {\n      return {\n        ...defaultCheckpointingOptions,\n        maxRuntime: defaultMaxRuntime,\n      };\n    }\n\n    return {\n      bufferedSteps:\n        userCfg.bufferedSteps ?? defaultCheckpointingOptions.bufferedSteps,\n      maxRuntime: userCfg.maxRuntime ?? defaultMaxRuntime,\n      maxInterval:\n        userCfg.maxInterval ?? defaultCheckpointingOptions.maxInterval,\n    };\n  }\n}\n\n/**\n * A stateless Inngest function, wrapping up function configuration and any\n * in-memory steps to run when triggered.\n *\n * This function can be \"registered\" to create a handler that Inngest can\n * trigger remotely.\n *\n * @public\n */\nexport namespace InngestFunction {\n  export const Tag = \"Inngest.Function\" as const;\n\n  /**\n   * Represents any `InngestFunction` instance, regardless of generics and\n   * inference.\n   */\n  export type Any = InngestFunction<\n    // biome-ignore lint/suspicious/noExplicitAny: intentional\n    InngestFunction.Options<any, any>,\n    Handler.Any,\n    Handler.Any,\n    // biome-ignore lint/suspicious/noExplicitAny: intentional\n    any,\n    // biome-ignore lint/suspicious/noExplicitAny: intentional\n    any\n  >;\n\n  export interface Like {\n    readonly [Symbol.toStringTag]: typeof InngestFunction.Tag;\n  }\n\n  /**\n   * A user-friendly method of specifying a trigger for an Inngest function.\n   *\n   * @public\n   */\n  export type Trigger<TName extends string> = StrictUnion<\n    | {\n        event: TName | EventTypeWithAnySchema<TName>;\n        if?: string;\n      }\n    | {\n        cron: string;\n      }\n  >;\n\n  export type GetOptions<T extends InngestFunction.Any> =\n    // biome-ignore lint/suspicious/noExplicitAny: intentional\n    T extends InngestFunction<infer O, any, any, any, any> ? O : never;\n\n  /**\n   * A set of options for configuring an Inngest function.\n   *\n   * @public\n   */\n  export interface Options<\n    TTriggers extends\n      InngestFunction.Trigger<string>[] = InngestFunction.Trigger<string>[],\n    TFailureHandler extends Handler.Any = Handler.Any,\n  > {\n    triggers?: TTriggers;\n\n    /**\n     * An unique ID used to identify the function. This is used internally for\n     * versioning and referring to your function, so should not change between\n     * deployments.\n     *\n     * If you'd like to set a prettier name for your function, use the `name`\n     * option.\n     */\n    id: string;\n\n    /**\n     * A name for the function as it will appear in the Inngest Cloud UI.\n     */\n    name?: string;\n\n    /**\n     * A description of the function.\n     */\n    description?: string;\n\n    /**\n     * Concurrency specifies a limit on the total number of concurrent steps that\n     * can occur across all runs of the function.  A value of 0 (or undefined) means\n     * use the maximum available concurrency.\n     *\n     * Specifying just a number means specifying only the concurrency limit. A\n     * maximum of two concurrency options can be specified.\n     */\n    concurrency?:\n      | number\n      | ConcurrencyOption\n      | RecursiveTuple<ConcurrencyOption, 2>;\n\n    /**\n     * batchEvents specifies the batch configuration on when this function\n     * should be invoked when one of the requirements are fulfilled.\n     */\n    batchEvents?: {\n      /**\n       * The maximum number of events to be consumed in one batch.\n       * Check the pricing page to verify the limit for each plan.\n       */\n      maxSize: number;\n\n      /**\n       * How long to wait before invoking the function with a list of events.\n       * If timeout is reached, the function will be invoked with a batch\n       * even if it's not filled up to `maxSize`.\n       *\n       * Expects a time string such as 1s, 60s or 15m15s.\n       */\n      timeout: TimeStrBatch;\n\n      /**\n       * An optional key to use for batching.\n       *\n       * See [batch documentation](https://innge.st/batching) for more\n       * information on how to use `key` expressions.\n       */\n      key?: string;\n\n      /**\n       * An optional boolean expression to determine an event's eligibility for batching\n       *\n       * See [batch documentation](https://innge.st/batching) for more\n       * information on how to use `if` expressions.\n       */\n      if?: string;\n    };\n\n    /**\n     * Allow the specification of an idempotency key using event data. If\n     * specified, this overrides the `rateLimit` object.\n     */\n    idempotency?: string;\n\n    /**\n     * Rate limit function runs, only running them a given number of times (limit) per\n     * period.  Note that rate limit is a lossy, hard limit.  Once the limit is hit,\n     * new runs will be skipped.  To enqueue work when a rate limit is hit, use the\n     * {@link throttle} parameter.\n     */\n    rateLimit?: {\n      /**\n       * An optional key to use for rate limiting, similar to idempotency.\n       */\n      key?: string;\n\n      /**\n       * The number of times to allow the function to run per the given `period`.\n       */\n      limit: number;\n\n      /**\n       * The period of time to allow the function to run `limit` times.\n       */\n      period: TimeStr;\n    };\n\n    /**\n     * Throttles function runs, only running them a given number of times (limit) per\n     * period.  Once the limit is hit, new runs will be enqueued and will start when there's\n     * capacity.  This may lead to a large backlog.  For hard rate limiting, use the\n     * {@link rateLimit} parameter.\n     */\n    throttle?: {\n      /**\n       *  An optional expression which returns a throttling key for controlling throttling.\n       *  Every unique key is its own throttle limit.  Event data may be used within this\n       *  expression, eg \"event.data.user_id\".\n       */\n      key?: string;\n\n      /**\n       * The total number of runs allowed to start within the given `period`.  The limit is\n       * applied evenly over the period.\n       */\n      limit: number;\n\n      /**\n       * The period of time for the rate limit.  Run starts are evenly spaced through\n       * the given period.  The minimum granularity is 1 second.\n       */\n      period: TimeStr;\n\n      /**\n       * The number of runs allowed to start in the given window in a single burst.\n       * A burst > 1 bypasses smoothing for the burst and allows many runs to start\n       * at once, if desired.  Defaults to 1, which disables bursting.\n       */\n      burst?: number;\n    };\n\n    /**\n     * Debounce delays functions for the `period` specified. If an event is sent,\n     * the function will not run until at least `period` has elapsed.\n     *\n     * If any new events are received that match the same debounce `key`, the\n     * function is rescheduled for another `period` delay, and the triggering\n     * event is replaced with the latest event received.\n     *\n     * See the [Debounce documentation](https://innge.st/debounce) for more\n     * information.\n     */\n    debounce?: {\n      /**\n       * An optional key to use for debouncing.\n       *\n       * See [Debounce documentation](https://innge.st/debounce) for more\n       * information on how to use `key` expressions.\n       */\n      key?: string;\n\n      /**\n       * The period of time to delay after receiving the last trigger to run the\n       * function.\n       *\n       * See [Debounce documentation](https://innge.st/debounce) for more\n       * information.\n       */\n      period: TimeStr;\n\n      /**\n       * The maximum time that a debounce can be extended before running.\n       * If events are continually received within the given period, a function\n       * will always run after the given timeout period.\n       *\n       * See [Debounce documentation](https://innge.st/debounce) for more\n       * information.\n       */\n      timeout?: TimeStr;\n    };\n\n    /**\n     * Configure how the priority of a function run is decided when multiple\n     * functions are triggered at the same time.\n     *\n     * See the [Priority documentation](https://innge.st/priority) for more\n     * information.\n     */\n    priority?: {\n      /**\n       * An expression to use to determine the priority of a function run. The\n       * expression can return a number between `-600` and `600`, where `600`\n       * declares that this run should be executed before any others enqueued in\n       * the last 600 seconds (10 minutes), and `-600` declares that this run\n       * should be executed after any others enqueued in the last 600 seconds.\n       *\n       * See the [Priority documentation](https://innge.st/priority) for more\n       * information.\n       */\n      run?: string;\n    };\n\n    /**\n     * Configure timeouts for the function.  If any of the timeouts are hit, the\n     * function run will be cancelled.\n     */\n    timeouts?: {\n      /**\n       * Start represents the timeout for starting a function.  If the time\n       * between scheduling and starting a function exceeds this value, the\n       * function will be cancelled.\n       *\n       * This is, essentially, the amount of time that a function sits in the\n       * queue before starting.\n       *\n       * A function may exceed this duration because of concurrency limits,\n       * throttling, etc.\n       */\n      start?: TimeStr;\n\n      /**\n       * Finish represents the time between a function starting and the function\n       * finishing. If a function takes longer than this time to finish, the\n       * function is marked as cancelled.\n       *\n       * The start time is taken from the time that the first successful\n       * function request begins, and does not include the time spent in the\n       * queue before the function starts.\n       *\n       * Note that if the final request to a function begins before this\n       * timeout, and completes after this timeout, the function will succeed.\n       */\n      finish?: TimeStr;\n    };\n\n    /**\n     * Ensures that only one run of the function is active at a time for a given key.\n     * If a new run is triggered while another is still in progress with the same key,\n     * the new run will either be skipped or replace the active one, depending on the mode.\n     *\n     * This is useful for deduplication or enforcing exclusive execution.\n     */\n    singleton?: {\n      /**\n       * An optional key expression used to scope singleton execution.\n       * Each unique key has its own singleton lock. Event data can be referenced,\n       * e.g. \"event.data.user_id\".\n       */\n      key?: string;\n\n      /**\n       * Determines how to handle new runs when one is already active for the same key.\n       * - `\"skip\"` skips the new run.\n       * - `\"cancel\"` cancels the existing run and starts the new one.\n       */\n      mode: \"skip\" | \"cancel\";\n    };\n\n    cancelOn?: Cancellation[];\n\n    /**\n     * Specifies the maximum number of retries for all steps across this function.\n     *\n     * Can be a number from `0` to `20`. Defaults to `3`.\n     */\n    retries?:\n      | 0\n      | 1\n      | 2\n      | 3\n      | 4\n      | 5\n      | 6\n      | 7\n      | 8\n      | 9\n      | 10\n      | 11\n      | 12\n      | 13\n      | 14\n      | 15\n      | 16\n      | 17\n      | 18\n      | 19\n      | 20;\n\n    /**\n     * Provide a function to be called if your function fails, meaning\n     * that it ran out of retries and was unable to complete successfully.\n     *\n     * This is useful for sending warning notifications or cleaning up\n     * after a failure and supports all the same functionality as a\n     * regular handler.\n     */\n    onFailure?: TFailureHandler;\n\n    /**\n     * Define a set of middleware that can be registered to hook into\n     * various lifecycles of the SDK and affect input and output of\n     * Inngest functionality.\n     *\n     * See {@link https://innge.st/middleware}\n     */\n    middleware?: Middleware.Class[];\n\n    /**\n     * Optimizes parallel steps to reduce traffic during `Promise` resolution,\n     * reducing time and requests per run. `Promise.*()` waits for all promises\n     * to settle before resolving. Use `group.parallel()` for `Promise.race()`\n     * semantics.\n     *\n     * Overrides the client-level setting.\n     *\n     * @default true\n     */\n    optimizeParallelism?: boolean;\n\n    /**\n     * Whether or not to use checkpointing for this function's executions.\n     *\n     * If `true`, enables checkpointing with default settings, which is a safe,\n     * blocking version of checkpointing, where we check in with Inngest after\n     * every step is run.\n     *\n     * If an object, you can tweak the settings to batch, set a maximum runtime\n     * before going async, and more. Note that if your server dies before the\n     * checkpoint completes, step data will be lost and steps will be rerun.\n     *\n     * We recommend starting with the default `true` configuration and only tweak\n     * the parameters directly if necessary.\n     *\n     * @deprecated Use `checkpointing` instead.\n     */\n    experimentalCheckpointing?: CheckpointingOptions;\n\n    /**\n     * Whether or not to use checkpointing for this function's executions.\n     *\n     * If `false`, disables checkpointing.\n     *\n     * If `true`, enables checkpointing with default settings, which is a safe,\n     * blocking version of checkpointing, where we check in with Inngest after\n     * every step is run.\n     *\n     * If an object, you can tweak the settings to batch, set a maximum runtime\n     * before going async, and more. Note that if your server dies before the\n     * checkpoint completes, step data will be lost and steps will be rerun.\n     *\n     * We recommend starting with the default `true` configuration and only tweak\n     * the parameters directly if necessary.\n     *\n     * @default true\n     */\n    checkpointing?: CheckpointingOptions;\n  }\n}\n\nexport type CreateExecutionOptions = {\n  partialOptions: Omit<InngestExecutionOptions, \"fn\">;\n};\n"],"mappings":"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"}