inngest 4.2.6 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/api/schema.d.cts +2 -2
  3. package/api/schema.d.cts.map +1 -1
  4. package/api/schema.d.ts +2 -2
  5. package/api/schema.d.ts.map +1 -1
  6. package/components/DeferredFunction.cjs +66 -0
  7. package/components/DeferredFunction.cjs.map +1 -0
  8. package/components/DeferredFunction.d.cts +99 -0
  9. package/components/DeferredFunction.d.cts.map +1 -0
  10. package/components/DeferredFunction.d.ts +99 -0
  11. package/components/DeferredFunction.d.ts.map +1 -0
  12. package/components/DeferredFunction.js +65 -0
  13. package/components/DeferredFunction.js.map +1 -0
  14. package/components/Inngest.cjs +5 -2
  15. package/components/Inngest.cjs.map +1 -1
  16. package/components/Inngest.d.cts +11 -4
  17. package/components/Inngest.d.cts.map +1 -1
  18. package/components/Inngest.d.ts +11 -4
  19. package/components/Inngest.d.ts.map +1 -1
  20. package/components/Inngest.js +5 -2
  21. package/components/Inngest.js.map +1 -1
  22. package/components/InngestCommHandler.cjs +28 -23
  23. package/components/InngestCommHandler.cjs.map +1 -1
  24. package/components/InngestCommHandler.d.cts +9 -4
  25. package/components/InngestCommHandler.d.cts.map +1 -1
  26. package/components/InngestCommHandler.d.ts +9 -4
  27. package/components/InngestCommHandler.d.ts.map +1 -1
  28. package/components/InngestCommHandler.js +28 -23
  29. package/components/InngestCommHandler.js.map +1 -1
  30. package/components/InngestFunction.cjs +27 -19
  31. package/components/InngestFunction.cjs.map +1 -1
  32. package/components/InngestFunction.d.cts +6 -1
  33. package/components/InngestFunction.d.cts.map +1 -1
  34. package/components/InngestFunction.d.ts +6 -1
  35. package/components/InngestFunction.d.ts.map +1 -1
  36. package/components/InngestFunction.js +27 -19
  37. package/components/InngestFunction.js.map +1 -1
  38. package/components/InngestGroupTools.cjs +1 -1
  39. package/components/InngestGroupTools.cjs.map +1 -1
  40. package/components/InngestGroupTools.js +1 -1
  41. package/components/InngestGroupTools.js.map +1 -1
  42. package/components/InngestStepTools.cjs +3 -7
  43. package/components/InngestStepTools.cjs.map +1 -1
  44. package/components/InngestStepTools.d.cts +10 -7
  45. package/components/InngestStepTools.d.cts.map +1 -1
  46. package/components/InngestStepTools.d.ts +10 -7
  47. package/components/InngestStepTools.d.ts.map +1 -1
  48. package/components/InngestStepTools.js +3 -7
  49. package/components/InngestStepTools.js.map +1 -1
  50. package/components/connect/config.cjs +2 -0
  51. package/components/connect/config.cjs.map +1 -1
  52. package/components/connect/config.js +2 -0
  53. package/components/connect/config.js.map +1 -1
  54. package/components/connect/strategies/core/connection.cjs +91 -11
  55. package/components/connect/strategies/core/connection.cjs.map +1 -1
  56. package/components/connect/strategies/core/connection.js +91 -11
  57. package/components/connect/strategies/core/connection.js.map +1 -1
  58. package/components/connect/strategies/core/heartbeat.cjs +2 -1
  59. package/components/connect/strategies/core/heartbeat.cjs.map +1 -1
  60. package/components/connect/strategies/core/heartbeat.js +2 -1
  61. package/components/connect/strategies/core/heartbeat.js.map +1 -1
  62. package/components/connect/strategies/core/requestProcessor.cjs +27 -4
  63. package/components/connect/strategies/core/requestProcessor.cjs.map +1 -1
  64. package/components/connect/strategies/core/requestProcessor.js +27 -4
  65. package/components/connect/strategies/core/requestProcessor.js.map +1 -1
  66. package/components/connect/strategies/core/types.cjs +21 -0
  67. package/components/connect/strategies/core/types.cjs.map +1 -0
  68. package/components/connect/strategies/core/types.js +20 -0
  69. package/components/connect/strategies/core/types.js.map +1 -0
  70. package/components/connect/types.cjs.map +1 -1
  71. package/components/connect/types.d.cts +18 -0
  72. package/components/connect/types.d.cts.map +1 -1
  73. package/components/connect/types.d.ts +18 -0
  74. package/components/connect/types.d.ts.map +1 -1
  75. package/components/connect/types.js.map +1 -1
  76. package/components/execution/InngestExecution.cjs.map +1 -1
  77. package/components/execution/InngestExecution.d.cts +19 -2
  78. package/components/execution/InngestExecution.d.cts.map +1 -1
  79. package/components/execution/InngestExecution.d.ts +19 -2
  80. package/components/execution/InngestExecution.d.ts.map +1 -1
  81. package/components/execution/InngestExecution.js.map +1 -1
  82. package/components/execution/engine.cjs +233 -28
  83. package/components/execution/engine.cjs.map +1 -1
  84. package/components/execution/engine.d.cts +14 -0
  85. package/components/execution/engine.d.cts.map +1 -1
  86. package/components/execution/engine.d.ts +14 -0
  87. package/components/execution/engine.d.ts.map +1 -1
  88. package/components/execution/engine.js +233 -28
  89. package/components/execution/engine.js.map +1 -1
  90. package/components/execution/lazyOps.cjs +64 -0
  91. package/components/execution/lazyOps.cjs.map +1 -0
  92. package/components/execution/lazyOps.d.cts +42 -0
  93. package/components/execution/lazyOps.d.cts.map +1 -0
  94. package/components/execution/lazyOps.d.ts +42 -0
  95. package/components/execution/lazyOps.d.ts.map +1 -0
  96. package/components/execution/lazyOps.js +63 -0
  97. package/components/execution/lazyOps.js.map +1 -0
  98. package/components/execution/otel/middleware.d.cts +14 -5
  99. package/components/execution/otel/middleware.d.cts.map +1 -1
  100. package/components/execution/otel/middleware.d.ts +14 -5
  101. package/components/execution/otel/middleware.d.ts.map +1 -1
  102. package/components/middleware/manager.cjs +1 -1
  103. package/components/middleware/manager.cjs.map +1 -1
  104. package/components/middleware/manager.js +2 -2
  105. package/components/middleware/manager.js.map +1 -1
  106. package/components/middleware/middleware.cjs.map +1 -1
  107. package/components/middleware/middleware.d.cts +1 -1
  108. package/components/middleware/middleware.d.cts.map +1 -1
  109. package/components/middleware/middleware.d.ts +1 -1
  110. package/components/middleware/middleware.d.ts.map +1 -1
  111. package/components/middleware/middleware.js.map +1 -1
  112. package/components/middleware/utils.cjs +5 -3
  113. package/components/middleware/utils.cjs.map +1 -1
  114. package/components/middleware/utils.js +5 -3
  115. package/components/middleware/utils.js.map +1 -1
  116. package/components/triggers/typeHelpers.cjs.map +1 -1
  117. package/components/triggers/typeHelpers.d.cts +11 -0
  118. package/components/triggers/typeHelpers.d.cts.map +1 -1
  119. package/components/triggers/typeHelpers.d.ts +11 -0
  120. package/components/triggers/typeHelpers.d.ts.map +1 -1
  121. package/components/triggers/typeHelpers.js.map +1 -1
  122. package/experimental.cjs +3 -0
  123. package/experimental.d.cts +2 -1
  124. package/experimental.d.ts +2 -1
  125. package/experimental.js +2 -1
  126. package/helpers/consts.cjs +6 -0
  127. package/helpers/consts.cjs.map +1 -1
  128. package/helpers/consts.d.cts +6 -0
  129. package/helpers/consts.d.cts.map +1 -1
  130. package/helpers/consts.d.ts +6 -0
  131. package/helpers/consts.d.ts.map +1 -1
  132. package/helpers/consts.js +6 -0
  133. package/helpers/consts.js.map +1 -1
  134. package/helpers/functions.cjs +1 -0
  135. package/helpers/functions.cjs.map +1 -1
  136. package/helpers/functions.js +1 -0
  137. package/helpers/functions.js.map +1 -1
  138. package/helpers/marker.cjs +21 -0
  139. package/helpers/marker.cjs.map +1 -0
  140. package/helpers/marker.d.cts +12 -0
  141. package/helpers/marker.d.cts.map +1 -0
  142. package/helpers/marker.d.ts +12 -0
  143. package/helpers/marker.d.ts.map +1 -0
  144. package/helpers/marker.js +19 -0
  145. package/helpers/marker.js.map +1 -0
  146. package/helpers/strings.cjs +10 -4
  147. package/helpers/strings.cjs.map +1 -1
  148. package/helpers/strings.d.cts.map +1 -1
  149. package/helpers/strings.d.ts.map +1 -1
  150. package/helpers/strings.js +10 -4
  151. package/helpers/strings.js.map +1 -1
  152. package/helpers/temporal.cjs +2 -0
  153. package/helpers/temporal.d.ts +3 -0
  154. package/helpers/temporal.d.ts.map +1 -1
  155. package/helpers/temporal.js +1 -1
  156. package/package.json +2 -2
  157. package/proto/src/components/connect/protobuf/connect.cjs +11 -2
  158. package/proto/src/components/connect/protobuf/connect.cjs.map +1 -1
  159. package/proto/src/components/connect/protobuf/connect.js +11 -2
  160. package/proto/src/components/connect/protobuf/connect.js.map +1 -1
  161. package/react.d.cts.map +1 -1
  162. package/types.cjs +2 -0
  163. package/types.cjs.map +1 -1
  164. package/types.d.cts +43 -8
  165. package/types.d.cts.map +1 -1
  166. package/types.d.ts +43 -8
  167. package/types.d.ts.map +1 -1
  168. package/types.js +2 -0
  169. package/types.js.map +1 -1
  170. package/version.cjs +1 -1
  171. package/version.cjs.map +1 -1
  172. package/version.d.cts +1 -1
  173. package/version.d.ts +1 -1
  174. package/version.js +1 -1
  175. package/version.js.map +1 -1
@@ -76,25 +76,7 @@ var InngestFunction = class InngestFunction {
76
76
  * configuration.
77
77
  */
78
78
  const retries = typeof attempts === "undefined" ? void 0 : { attempts };
79
- const triggers = [];
80
- for (const trigger of this.opts.triggers ?? []) {
81
- if (trigger.cron) {
82
- const cronTrigger = trigger;
83
- triggers.push({
84
- cron: cronTrigger.cron,
85
- ...cronTrigger.jitter ? { jitter: cronTrigger.jitter } : {}
86
- });
87
- continue;
88
- }
89
- if (!trigger.event) continue;
90
- let eventName = trigger.event;
91
- if (eventName instanceof require_triggers.EventType) eventName = eventName.name;
92
- if (eventName === require_consts.internalEvents.FunctionInvoked) continue;
93
- triggers.push({
94
- event: eventName,
95
- expression: trigger.if
96
- });
97
- }
79
+ const triggers = this.getConfigTriggers(fnId);
98
80
  const fn = {
99
81
  id: fnId,
100
82
  name: this.name,
@@ -154,6 +136,32 @@ var InngestFunction = class InngestFunction {
154
136
  }
155
137
  return config;
156
138
  }
139
+ /**
140
+ * Build the trigger list for this function's `getConfig` payload. Subclasses
141
+ * (e.g. `DeferredFunction`) override this to emit implicit triggers.
142
+ */
143
+ getConfigTriggers(_fnId) {
144
+ const triggers = [];
145
+ for (const trigger of this.opts.triggers ?? []) {
146
+ if (trigger.cron) {
147
+ const cronTrigger = trigger;
148
+ triggers.push({
149
+ cron: cronTrigger.cron,
150
+ ...cronTrigger.jitter ? { jitter: cronTrigger.jitter } : {}
151
+ });
152
+ continue;
153
+ }
154
+ if (!trigger.event) continue;
155
+ let eventName = trigger.event;
156
+ if (eventName instanceof require_triggers.EventType) eventName = eventName.name;
157
+ if (eventName === require_consts.internalEvents.FunctionInvoked) continue;
158
+ triggers.push({
159
+ event: eventName,
160
+ expression: trigger.if
161
+ });
162
+ }
163
+ return triggers;
164
+ }
157
165
  createExecution(opts) {
158
166
  return require_engine.createExecutionEngine({
159
167
  fn: this,
@@ -1 +1 @@
1
- {"version":3,"file":"InngestFunction.cjs","names":["queryKeys","triggers: FunctionConfig[\"triggers\"]","EventType","internalEvents","fn: FunctionConfig","eventName: string","ret: NonNullable<FunctionConfig[\"cancel\"]>[number]","timeStr","config: FunctionConfig[]","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: FunctionConfig[\"triggers\"] = [];\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 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 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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"}
1
+ {"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":";;;;;;;;;;;;;;;;AAkCA,IAAa,kBAAb,MAAa,gBAQb;CACE,OAAO,SAAS;CAChB,OAAO,gBAAgB;CAEvB,KAAK,OAAO,eAA2C;AACrD,SAAO,gBAAgB;;CAGzB,AAAgB;CAEhB,AAAiB;CACjB,AAAiB;CACjB,AAAmB;;;;;;;;CASnB,YACE,QAKA,MACA,IACA;AACA,OAAK,SAAS;AACd,OAAK,OAAO;AACZ,OAAK,KAAK;AACV,OAAK,cAAc,KAAK,KAAK;;;;;CAM/B,AAAO,GAAG,QAAyB;AACjC,SAAO,CAAC,QAAQ,KAAK,KAAK,GAAG,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;;;;;;CAOzD,IAAc,aAAqB;AACjC,SAAO,KAAK,GAAG,KAAK,OAAO,GAAG;;;;;CAMhC,IAAW,OAAe;AACxB,SAAO,KAAK,KAAK,QAAQ,KAAK,IAAI;;;;;CAMpC,IAAW,cAAkC;AAC3C,SAAO,KAAK,KAAK;;;;;CAQnB,AAAQ,UAAU,EAChB,SACA,WACA,aAkBmB;EACnB,MAAM,OAAO,KAAK,GAAG,UAAU;EAC/B,MAAM,UAAU,IAAI,IAAI,QAAQ,KAAK;AACrC,UAAQ,aAAa,IAAIA,yBAAU,MAAM,KAAK;AAC9C,UAAQ,aAAa,IAAIA,yBAAU,QAAQ,gBAAgB,OAAO;EAElE,MAAM,EACJ,SAAS,UACT,UACA,aACA,aACA,WACA,UACA,aACA,UACA,UACA,UACA,cACE,KAAK;;;;;EAMT,MAAM,UAAU,OAAO,aAAa,cAAc,SAAY,EAAE,UAAU;EAE1E,MAAM,WAAW,KAAK,kBAAkB,KAAK;EAE7C,MAAMC,KAAqB;GACzB,IAAI;GACJ,MAAM,KAAK;GACX;GACA,OAAO,GACJ,gBAAgB,SAAS;IACxB,IAAI,gBAAgB;IACpB,MAAM,gBAAgB;IACtB,SAAS;KACP,MAAM,YAAY,OAAO;KACzB,KAAK,QAAQ;KACd;IACD;IACD,EACF;GACD;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;AAED,MAAI,SACF,IAAG,SAAS,SAAS,KAAK,EAAE,OAAO,SAAS,IAAI,OAAO,YAAY;GACjE,IAAIC;AACJ,OAAI,OAAO,UAAU,SACnB,aAAY;OAEZ,aAAY,MAAM;GAGpB,MAAMC,MAAqD,EACzD,OAAO,WACR;AAED,OAAI,QACF,KAAI,UAAUC,wBAAQ,QAAQ;AAGhC,OAAI,MACF,KAAI,KAAK,SAAS,MAAM,YAAY;YAC3B,MACT,KAAI,KAAK;AAGX,UAAO;KACN,EAAE,CAAC;EAGR,MAAMC,SAA2B,CAAC,GAAG;AAErC,MAAI,KAAK,aAAa;GACpB,MAAM,KAAK,GAAG,GAAG,KAAK,gBAAgB;GACtC,MAAM,OAAO,GAAG,GAAG,QAAQ,GAAG,GAAG;GAEjC,MAAM,iBAAiB,IAAI,IAAI,QAAQ,KAAK;AAC5C,kBAAe,aAAa,IAAIL,yBAAU,MAAM,GAAG;AAEnD,UAAO,KAAK;IACV;IACA;IACA,UAAU,CACR;KACE,OAAOM,8BAAe;KACtB,YAAY,8BAA8B,KAAK;KAChD,CACF;IACD,OAAO,GACJ,gBAAgB,SAAS;KACxB,IAAI,gBAAgB;KACpB,MAAM,gBAAgB;KACtB,SAAS;MACP,MAAM;MACN,KAAK,eAAe;MACrB;KACD,SAAS,EAAE,UAAU,GAAG;KACzB,EACF;IACF,CAAC;;AAGJ,SAAO;;;;;;CAOT,AAAU,kBAAkB,OAA2C;EACrE,MAAMC,WAAuC,EAAE;AAE/C,OAAK,MAAM,WAAW,KAAK,KAAK,YAAY,EAAE,EAAE;AAC9C,OAAI,QAAQ,MAAM;IAChB,MAAM,cAAc;AACpB,aAAS,KAAK;KACZ,MAAM,YAAY;KAClB,GAAI,YAAY,SAAS,EAAE,QAAQ,YAAY,QAAQ,GAAG,EAAE;KAC7D,CAAC;AACF;;AAGF,OAAI,CAAC,QAAQ,MACX;GAMF,IAAI,YAAY,QAAQ;AACxB,OAAI,qBAAqBC,2BACvB,aAAY,UAAU;AAExB,OAAI,cAAcF,8BAAe,gBAC/B;AAGF,YAAS,KAAK;IAAE,OAAO;IAAW,YAAY,QAAQ;IAAI,CAAC;;AAG7D,SAAO;;CAGT,AAAU,gBAAgB,MAAiD;AAMzE,SAAOG,qCALkC;GACvC,IAAI;GACJ,GAAG,KAAK;GACT,CAEoC;;CAIvC,AAAQ,4BAAqC;AAE3C,SACE,KAAK,KAAK,uBACV,KAAK,OAAO,WAAW,uBACvB;;CAKJ,AAAQ,sBACN,kBACA,cACA,2BACA,mBAC0C;AAC1C,MAAI,oBAAoB,CAAC,gBAAgB,0BACvC;EAIF,MAAM,UACJ,KAAK,KAAK,iBACV,KAAK,OAAO,WAAW,iBACvB,KAAK,KAAK,6BACV,KAAK,OAAO,WAAW,6BACvB;AAEF,MAAI,CAAC,QAEH;AAGF,MAAI,YAAY,KACd,QAAO;GACL,GAAGC;GACH,YAAY;GACb;AAGH,SAAO;GACL,eACE,QAAQ,iBAAiBA,0CAA4B;GACvD,YAAY,QAAQ,cAAc;GAClC,aACE,QAAQ,eAAeA,0CAA4B;GACtD;;;;wBAcgB"}
@@ -2,7 +2,7 @@ import { RecursiveTuple, StrictUnion } from "../helpers/types.cjs";
2
2
  import { Middleware } from "./middleware/middleware.cjs";
3
3
  import { EventTypeWithAnySchema } from "./triggers/triggers.cjs";
4
4
  import { IInngestExecution, InngestExecutionOptions } from "./execution/InngestExecution.cjs";
5
- import { Cancellation, CheckpointingOptions, ConcurrencyOption, Handler, TimeStr, TimeStrBatch } from "../types.cjs";
5
+ import { Cancellation, CheckpointingOptions, ConcurrencyOption, FunctionConfig, Handler, TimeStr, TimeStrBatch } from "../types.cjs";
6
6
  import { Inngest } from "./Inngest.cjs";
7
7
 
8
8
  //#region src/components/InngestFunction.d.ts
@@ -57,6 +57,11 @@ declare class InngestFunction<TFnOpts extends InngestFunction.Options<TTriggers,
57
57
  * Retrieve the Inngest config for this function.
58
58
  */
59
59
  private getConfig;
60
+ /**
61
+ * Build the trigger list for this function's `getConfig` payload. Subclasses
62
+ * (e.g. `DeferredFunction`) override this to emit implicit triggers.
63
+ */
64
+ protected getConfigTriggers(_fnId: string): FunctionConfig["triggers"];
60
65
  protected createExecution(opts: CreateExecutionOptions): IInngestExecution;
61
66
  private shouldOptimizeParallelism;
62
67
  private shouldAsyncCheckpoint;
@@ -1 +1 @@
1
- {"version":3,"file":"InngestFunction.d.cts","names":[],"sources":["../../src/components/InngestFunction.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAkCA;;;;;;;AAIkB,cAJL,eAIa,CAAA,gBAHR,eAAA,CAAgB,OAGR,CAHgB,SAGhB,EAH2B,eAG3B,CAAA,EAAA,iBAFP,OAAA,CAAQ,GAED,EAAA,wBADA,OAAA,CAAQ,GACR,EAAA,gBAAR,OAAA,CAAQ,GAAA,GAAM,OAAA,CAAQ,GAAd,EAAA,kBAEtB,eAAA,CAAgB,OAFM,CAAA,MAAA,CAAA,EAAA,GAEc,eAAA,CAAgB,OAF9B,CAAA,MAAA,CAAA,EAAA,CAAA,YAGb,eAAA,CAAgB,IAHH,CAAA;SAAM,MAAQ,EAAA,MAAA;SAEpC,aAAgB,EAAA,MAAA;OAMb,MAAA,CAAO,WAAA,GAN0C,EAAA,OAMnB,eAAA,CAAgB,GANG;WAMnB,IAAA,EAIb,OAJ6B;mBAAvC,EAAA;mBAIU,WAAA;qBAIK,MAAA,EAAA,OAAA;;;;;;;;EAmSZ,WAAA,CAAA,MAAe,EAzRpB,OAyRoB;EAAA;;;MAW5B,EA/RM,OA+RE,EAAA,EAAA,EA9RJ,QA8RI;;;;KAkBG,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;;;gBAUX,UAAA,CAAA,CAAA,EAAA,MAAA;;;;MASsC,IAAA,CAAA,CAAA,EAAA,MAAA;;;;MAmClC,WAAA,CAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;;;UAkEM,SAAA;YA2BA,eAAA,CAAA,IAAA,EArPoB,sBAqPpB,CAAA,EArP6C,iBAqP7C;UAqCA,yBAAA;UAUE,qBAAA;;;;;;;;;AAqLhB;;AACuB,kBArZN,eAAA,CAqZM;QAAL,GAAA,EAAA,kBAAA;EAAI;;;;aA9YF,gBAEhB,eAAA,CAAgB,mBAChB,OAAA,CAAQ,KACR,OAAA,CAAQ;;cAQE,MAAA,CAAO,WAAA,UAAqB,eAAA,CAAgB;;;;;;;uCAQZ;WAE/B,QAAQ,uBAAuB;;;;;4BAQX,eAAA,CAAgB,OAE/C,UAAU,+CAA+C;;;;;;sCASvD,eAAA,CAAgB,oBAAoB,eAAA,CAAgB,2CAC9B,OAAA,CAAQ,MAAM,OAAA,CAAQ;eAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgCP,oBACA,eAAe;;;;;;;;;;;;;;;;;;eAoBR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CD;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqCA;;;;;;;;;gBAUE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCF;;;;;;;;;;;;;eAcC;;;;;;;;;;;;;;;;;;;;;;;eA0BA;;;;;;;;;;;;;;;gBAsCC;;;;;;;;iBASC,UAAA,CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA8BI;;;;;;;;;;;;;;;;;;;oBAoBZ;;;KAIR,sBAAA;kBACM,KAAK"}
1
+ {"version":3,"file":"InngestFunction.d.cts","names":[],"sources":["../../src/components/InngestFunction.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAkCA;;;;;;;AAIkB,cAJL,eAIa,CAAA,gBAHR,eAAA,CAAgB,OAGR,CAHgB,SAGhB,EAH2B,eAG3B,CAAA,EAAA,iBAFP,OAAA,CAAQ,GAED,EAAA,wBADA,OAAA,CAAQ,GACR,EAAA,gBAAR,OAAA,CAAQ,GAAA,GAAM,OAAA,CAAQ,GAAd,EAAA,kBAEtB,eAAA,CAAgB,OAFM,CAAA,MAAA,CAAA,EAAA,GAEc,eAAA,CAAgB,OAF9B,CAAA,MAAA,CAAA,EAAA,CAAA,YAGb,eAAA,CAAgB,IAHH,CAAA;SAAM,MAAQ,EAAA,MAAA;SAEpC,aAAgB,EAAA,MAAA;OAMb,MAAA,CAAO,WAAA,GAN0C,EAAA,OAMnB,eAAA,CAAgB,GANG;WAMnB,IAAA,EAIb,OAJ6B;mBAAvC,EAAA;mBAIU,WAAA;qBAIK,MAAA,EAAA,OAAA;;;;;;;;EAbI,WAAA,CAAA,MAAA,EAuBrB,OAvBqB;EA2ThB;;;MAUb,EAzSM,OAySE,EAAA,EAAA,EAxSJ,QAwSI;;;;KASE,MAAO,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;;;gBAkBc,UAAgB,CAAA,CAAA,EAAA,MAAA;;;;MAW7C,IAAA,CAAA,CAAA,EAAA,MAAA;;;;MAGS,WAAA,CAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;;;UAqDA,SAAA;;;;;YA+JD,iBAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EA9WgC,cA8WhC,CAAA,UAAA,CAAA;YAcC,eAAA,CAAA,IAAA,EA1VmB,sBA0VnB,CAAA,EA1V4C,iBA0V5C;UA0BA,yBAAA;UAsCC,qBAAA;;;;;AA+DhB;;;;;;kBApZiB,eAAA;;;;;;aAOG,gBAEhB,eAAA,CAAgB,mBAChB,OAAA,CAAQ,KACR,OAAA,CAAQ;;cAQE,MAAA,CAAO,WAAA,UAAqB,eAAA,CAAgB;;;;;;;uCAQZ;WAE/B,QAAQ,uBAAuB;;;;;4BAQX,eAAA,CAAgB,OAE/C,UAAU,+CAA+C;;;;;;sCASvD,eAAA,CAAgB,oBAAoB,eAAA,CAAgB,2CAC9B,OAAA,CAAQ,MAAM,OAAA,CAAQ;eAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgCP,oBACA,eAAe;;;;;;;;;;;;;;;;;;eAoBR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CD;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqCA;;;;;;;;;gBAUE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCF;;;;;;;;;;;;;eAcC;;;;;;;;;;;;;;;;;;;;;;;eA0BA;;;;;;;;;;;;;;;gBAsCC;;;;;;;;iBASC,UAAA,CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA8BI;;;;;;;;;;;;;;;;;;;oBAoBZ;;;KAIR,sBAAA;kBACM,KAAK"}
@@ -2,7 +2,7 @@ import { RecursiveTuple, StrictUnion } from "../helpers/types.js";
2
2
  import { Middleware } from "./middleware/middleware.js";
3
3
  import { EventTypeWithAnySchema } from "./triggers/triggers.js";
4
4
  import { IInngestExecution, InngestExecutionOptions } from "./execution/InngestExecution.js";
5
- import { Cancellation, CheckpointingOptions, ConcurrencyOption, Handler, TimeStr, TimeStrBatch } from "../types.js";
5
+ import { Cancellation, CheckpointingOptions, ConcurrencyOption, FunctionConfig, Handler, TimeStr, TimeStrBatch } from "../types.js";
6
6
  import { Inngest } from "./Inngest.js";
7
7
 
8
8
  //#region src/components/InngestFunction.d.ts
@@ -57,6 +57,11 @@ declare class InngestFunction<TFnOpts extends InngestFunction.Options<TTriggers,
57
57
  * Retrieve the Inngest config for this function.
58
58
  */
59
59
  private getConfig;
60
+ /**
61
+ * Build the trigger list for this function's `getConfig` payload. Subclasses
62
+ * (e.g. `DeferredFunction`) override this to emit implicit triggers.
63
+ */
64
+ protected getConfigTriggers(_fnId: string): FunctionConfig["triggers"];
60
65
  protected createExecution(opts: CreateExecutionOptions): IInngestExecution;
61
66
  private shouldOptimizeParallelism;
62
67
  private shouldAsyncCheckpoint;
@@ -1 +1 @@
1
- {"version":3,"file":"InngestFunction.d.ts","names":[],"sources":["../../src/components/InngestFunction.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAkCA;;;;;;;AAIkB,cAJL,eAIa,CAAA,gBAHR,eAAA,CAAgB,OAGR,CAHgB,SAGhB,EAH2B,eAG3B,CAAA,EAAA,iBAFP,OAAA,CAAQ,GAED,EAAA,wBADA,OAAA,CAAQ,GACR,EAAA,gBAAR,OAAA,CAAQ,GAAA,GAAM,OAAA,CAAQ,GAAd,EAAA,kBAEtB,eAAA,CAAgB,OAFM,CAAA,MAAA,CAAA,EAAA,GAEc,eAAA,CAAgB,OAF9B,CAAA,MAAA,CAAA,EAAA,CAAA,YAGb,eAAA,CAAgB,IAHH,CAAA;SAAM,MAAQ,EAAA,MAAA;SAEpC,aAAgB,EAAA,MAAA;OAMb,MAAA,CAAO,WAAA,GAN0C,EAAA,OAMnB,eAAA,CAAgB,GANG;WAMnB,IAAA,EAIb,OAJ6B;mBAAvC,EAAA;mBAIU,WAAA;qBAIK,MAAA,EAAA,OAAA;;;;;;;;EAmSZ,WAAA,CAAA,MAAe,EAzRpB,OAyRoB;EAAA;;;MAW5B,EA/RM,OA+RE,EAAA,EAAA,EA9RJ,QA8RI;;;;KAkBG,MAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;;;gBAUX,UAAA,CAAA,CAAA,EAAA,MAAA;;;;MASsC,IAAA,CAAA,CAAA,EAAA,MAAA;;;;MAmClC,WAAA,CAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;;;UAkEM,SAAA;YA2BA,eAAA,CAAA,IAAA,EArPoB,sBAqPpB,CAAA,EArP6C,iBAqP7C;UAqCA,yBAAA;UAUE,qBAAA;;;;;;;;;AAqLhB;;AACuB,kBArZN,eAAA,CAqZM;QAAL,GAAA,EAAA,kBAAA;EAAI;;;;aA9YF,gBAEhB,eAAA,CAAgB,mBAChB,OAAA,CAAQ,KACR,OAAA,CAAQ;;cAQE,MAAA,CAAO,WAAA,UAAqB,eAAA,CAAgB;;;;;;;uCAQZ;WAE/B,QAAQ,uBAAuB;;;;;4BAQX,eAAA,CAAgB,OAE/C,UAAU,+CAA+C;;;;;;sCASvD,eAAA,CAAgB,oBAAoB,eAAA,CAAgB,2CAC9B,OAAA,CAAQ,MAAM,OAAA,CAAQ;eAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgCP,oBACA,eAAe;;;;;;;;;;;;;;;;;;eAoBR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CD;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqCA;;;;;;;;;gBAUE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCF;;;;;;;;;;;;;eAcC;;;;;;;;;;;;;;;;;;;;;;;eA0BA;;;;;;;;;;;;;;;gBAsCC;;;;;;;;iBASC,UAAA,CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA8BI;;;;;;;;;;;;;;;;;;;oBAoBZ;;;KAIR,sBAAA;kBACM,KAAK"}
1
+ {"version":3,"file":"InngestFunction.d.ts","names":[],"sources":["../../src/components/InngestFunction.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAkCA;;;;;;;AAIkB,cAJL,eAIa,CAAA,gBAHR,eAAA,CAAgB,OAGR,CAHgB,SAGhB,EAH2B,eAG3B,CAAA,EAAA,iBAFP,OAAA,CAAQ,GAED,EAAA,wBADA,OAAA,CAAQ,GACR,EAAA,gBAAR,OAAA,CAAQ,GAAA,GAAM,OAAA,CAAQ,GAAd,EAAA,kBAEtB,eAAA,CAAgB,OAFM,CAAA,MAAA,CAAA,EAAA,GAEc,eAAA,CAAgB,OAF9B,CAAA,MAAA,CAAA,EAAA,CAAA,YAGb,eAAA,CAAgB,IAHH,CAAA;SAAM,MAAQ,EAAA,MAAA;SAEpC,aAAgB,EAAA,MAAA;OAMb,MAAA,CAAO,WAAA,GAN0C,EAAA,OAMnB,eAAA,CAAgB,GANG;WAMnB,IAAA,EAIb,OAJ6B;mBAAvC,EAAA;mBAIU,WAAA;qBAIK,MAAA,EAAA,OAAA;;;;;;;;EAbI,WAAA,CAAA,MAAA,EAuBrB,OAvBqB;EA2ThB;;;MAUb,EAzSM,OAySE,EAAA,EAAA,EAxSJ,QAwSI;;;;KASE,MAAO,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;;;gBAkBc,UAAgB,CAAA,CAAA,EAAA,MAAA;;;;MAW7C,IAAA,CAAA,CAAA,EAAA,MAAA;;;;MAGS,WAAA,CAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;;;UAqDA,SAAA;;;;;YA+JD,iBAAA,CAAA,KAAA,EAAA,MAAA,CAAA,EA9WgC,cA8WhC,CAAA,UAAA,CAAA;YAcC,eAAA,CAAA,IAAA,EA1VmB,sBA0VnB,CAAA,EA1V4C,iBA0V5C;UA0BA,yBAAA;UAsCC,qBAAA;;;;;AA+DhB;;;;;;kBApZiB,eAAA;;;;;;aAOG,gBAEhB,eAAA,CAAgB,mBAChB,OAAA,CAAQ,KACR,OAAA,CAAQ;;cAQE,MAAA,CAAO,WAAA,UAAqB,eAAA,CAAgB;;;;;;;uCAQZ;WAE/B,QAAQ,uBAAuB;;;;;4BAQX,eAAA,CAAgB,OAE/C,UAAU,+CAA+C;;;;;;sCASvD,eAAA,CAAgB,oBAAoB,eAAA,CAAgB,2CAC9B,OAAA,CAAQ,MAAM,OAAA,CAAQ;eAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgCP,oBACA,eAAe;;;;;;;;;;;;;;;;;;eAoBR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CD;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqCA;;;;;;;;;gBAUE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCF;;;;;;;;;;;;;eAcC;;;;;;;;;;;;;;;;;;;;;;;eA0BA;;;;;;;;;;;;;;;gBAsCC;;;;;;;;iBASC,UAAA,CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA8BI;;;;;;;;;;;;;;;;;;;oBAoBZ;;;KAIR,sBAAA;kBACM,KAAK"}
@@ -76,25 +76,7 @@ var InngestFunction = class InngestFunction {
76
76
  * configuration.
77
77
  */
78
78
  const retries = typeof attempts === "undefined" ? void 0 : { attempts };
79
- const triggers = [];
80
- for (const trigger of this.opts.triggers ?? []) {
81
- if (trigger.cron) {
82
- const cronTrigger = trigger;
83
- triggers.push({
84
- cron: cronTrigger.cron,
85
- ...cronTrigger.jitter ? { jitter: cronTrigger.jitter } : {}
86
- });
87
- continue;
88
- }
89
- if (!trigger.event) continue;
90
- let eventName = trigger.event;
91
- if (eventName instanceof EventType) eventName = eventName.name;
92
- if (eventName === internalEvents.FunctionInvoked) continue;
93
- triggers.push({
94
- event: eventName,
95
- expression: trigger.if
96
- });
97
- }
79
+ const triggers = this.getConfigTriggers(fnId);
98
80
  const fn = {
99
81
  id: fnId,
100
82
  name: this.name,
@@ -154,6 +136,32 @@ var InngestFunction = class InngestFunction {
154
136
  }
155
137
  return config;
156
138
  }
139
+ /**
140
+ * Build the trigger list for this function's `getConfig` payload. Subclasses
141
+ * (e.g. `DeferredFunction`) override this to emit implicit triggers.
142
+ */
143
+ getConfigTriggers(_fnId) {
144
+ const triggers = [];
145
+ for (const trigger of this.opts.triggers ?? []) {
146
+ if (trigger.cron) {
147
+ const cronTrigger = trigger;
148
+ triggers.push({
149
+ cron: cronTrigger.cron,
150
+ ...cronTrigger.jitter ? { jitter: cronTrigger.jitter } : {}
151
+ });
152
+ continue;
153
+ }
154
+ if (!trigger.event) continue;
155
+ let eventName = trigger.event;
156
+ if (eventName instanceof EventType) eventName = eventName.name;
157
+ if (eventName === internalEvents.FunctionInvoked) continue;
158
+ triggers.push({
159
+ event: eventName,
160
+ expression: trigger.if
161
+ });
162
+ }
163
+ return triggers;
164
+ }
157
165
  createExecution(opts) {
158
166
  return createExecutionEngine({
159
167
  fn: this,
@@ -1 +1 @@
1
- {"version":3,"file":"InngestFunction.js","names":["triggers: FunctionConfig[\"triggers\"]","fn: FunctionConfig","eventName: string","ret: NonNullable<FunctionConfig[\"cancel\"]>[number]","config: FunctionConfig[]"],"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: FunctionConfig[\"triggers\"] = [];\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 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 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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"}
1
+ {"version":3,"file":"InngestFunction.js","names":["fn: FunctionConfig","eventName: string","ret: NonNullable<FunctionConfig[\"cancel\"]>[number]","config: FunctionConfig[]","triggers: FunctionConfig[\"triggers\"]"],"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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"}
@@ -75,7 +75,7 @@ const createGroupTools = (deps) => {
75
75
  if (execInstance && experimentStepHashedId) {
76
76
  execInstance.addMetadata(experimentStepHashedId, "inngest.experiment", "step", "merge", {
77
77
  experiment_name: stepOpts.id,
78
- variant_selected: result$1,
78
+ variant: result$1,
79
79
  selection_strategy: select.__experimentConfig.strategy,
80
80
  available_variants: variantNames,
81
81
  ...select.__experimentConfig.weights && { variant_weights: select.__experimentConfig.weights }
@@ -1 +1 @@
1
- {"version":3,"file":"InngestGroupTools.cjs","names":["options: ParallelOptions","getAsyncCtxSync","getAsyncLocalStorage","isALSFallback","nestedCtx: AsyncContext","experiment: GroupExperiment","getStepOptions","experimentStepHashedId: string | undefined","selectedVariant: string","currentCtx","selectCtx: AsyncContext","result","NonRetriableError","result: unknown"],"sources":["../../src/components/InngestGroupTools.ts"],"sourcesContent":["import type { IsNever } from \"../helpers/types.ts\";\nimport type { StepOptionsOrId } from \"../types.ts\";\nimport {\n type AsyncContext,\n getAsyncCtxSync,\n getAsyncLocalStorage,\n isALSFallback,\n} from \"./execution/als.ts\";\nimport { getStepOptions } from \"./InngestStepTools.ts\";\nimport { NonRetriableError } from \"./NonRetriableError.ts\";\n\n/**\n * Options for the `group.parallel()` helper.\n */\nexport interface ParallelOptions {\n /**\n * The parallel mode to apply to all steps created within the callback.\n *\n * - `\"race\"`: Steps will be executed with race semantics, meaning the first\n * step to complete will \"win\" and remaining steps may be cancelled.\n */\n mode?: \"race\";\n}\n\n/**\n * A helper that sets the parallel mode for all steps created within the\n * callback. This allows you to use native `Promise.race()` with cleaner syntax.\n *\n * @example\n * ```ts\n * // Defaults to \"race\" mode\n * const winner = await group.parallel(async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * step.run(\"c\", () => \"c\"),\n * ]);\n * });\n *\n * // Or explicitly specify the mode\n * const winner = await group.parallel({ mode: \"race\" }, async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * ]);\n * });\n * ```\n */\nconst parallel = async <T>(\n optionsOrCallback: ParallelOptions | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n): Promise<T> => {\n const options: ParallelOptions =\n typeof optionsOrCallback === \"function\" ? {} : optionsOrCallback;\n const callback =\n typeof optionsOrCallback === \"function\" ? optionsOrCallback : maybeCallback;\n\n if (!callback) {\n throw new Error(\"`group.parallel()` requires a callback function\");\n }\n\n const currentCtx = getAsyncCtxSync();\n\n if (!currentCtx?.execution) {\n throw new Error(\n \"`group.parallel()` must be called within an Inngest function execution\",\n );\n }\n\n const als = await getAsyncLocalStorage();\n\n if (isALSFallback()) {\n throw new Error(\n \"`group.parallel()` requires AsyncLocalStorage support, which is not available in this runtime. \" +\n \"Workaround: Pass `parallelMode` directly to each step:\\n\" +\n ' step.run({ id: \"my-step\", parallelMode: \"race\" }, fn)',\n );\n }\n\n // Create a new context with the parallelMode set\n const nestedCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution,\n parallelMode: options.mode ?? \"race\",\n },\n };\n\n // Run the callback inside the nested context\n return als.run(nestedCtx, callback);\n};\n\n/**\n * Configuration for how the experiment selects a variant.\n */\nexport interface ExperimentStrategyConfig {\n strategy: string;\n weights?: Record<string, number>;\n nullishBucket?: boolean;\n}\n\n/**\n * A callable selection function that also carries strategy metadata.\n */\nexport interface ExperimentSelectFn {\n (variantNames?: string[]): Promise<string> | string;\n __experimentConfig: ExperimentStrategyConfig;\n}\n\n/**\n * Options for `group.experiment()`.\n */\nexport interface ExperimentOptions<\n TVariants extends Record<string, () => unknown>,\n> {\n /**\n * A map of variant names to callbacks. The selected variant's callback will\n * be executed at the top level so that any `step.*` calls inside it go\n * through normal step discovery.\n */\n variants: TVariants;\n\n /**\n * A selection function that returns the name of the variant to execute.\n * The result is memoized via a step so the same variant is used on retries.\n */\n select: ExperimentSelectFn;\n}\n\n/**\n * Options for `group.experiment()` when `withVariant` is true, which causes\n * the return type to include both the result and the selected variant name.\n */\nexport interface ExperimentOptionsWithVariant<\n TVariants extends Record<string, () => unknown>,\n> extends ExperimentOptions<TVariants> {\n /**\n * When true, the return value includes the variant name alongside the result.\n */\n withVariant: true;\n}\n\n/**\n * Computes the return type of an experiment based on variant callbacks.\n *\n * When `TConstraint` is `never`, the return type is inferred as the union of\n * all variant callback return types. Otherwise `TConstraint` is used directly.\n */\nexport type VariantResult<\n TConstraint,\n TVariants extends Record<string, () => unknown>,\n> = IsNever<TConstraint> extends true\n ? Awaited<ReturnType<TVariants[keyof TVariants]>>\n : TConstraint;\n\n/**\n * Metadata values stored alongside the experiment step for UI rendering.\n */\nexport interface ExperimentMetadataValues {\n experiment_name: string;\n variant_selected: string;\n selection_strategy: string;\n available_variants: string[];\n variant_weights?: Record<string, number>;\n}\n\n/**\n * Overloaded interface for `group.experiment()`.\n */\nexport interface GroupExperiment {\n /**\n * Run an A/B experiment that selects and executes a variant. Returns both\n * the result and the selected variant name.\n */\n <TVariants extends Record<string, () => unknown>>(\n idOrOptions: StepOptionsOrId,\n options: ExperimentOptionsWithVariant<TVariants>,\n ): Promise<{\n result: VariantResult<never, TVariants>;\n variant: string;\n }>;\n\n /**\n * Run an A/B experiment that selects and executes a variant. Returns only\n * the variant callback's result.\n */\n <TVariants extends Record<string, () => unknown>>(\n idOrOptions: StepOptionsOrId,\n options: ExperimentOptions<TVariants>,\n ): Promise<VariantResult<never, TVariants>>;\n}\n\n/**\n * Tools for grouping and coordinating steps.\n *\n * @public\n */\nexport interface GroupTools {\n /**\n * Run a callback where all steps automatically receive a `parallelMode`\n * option, removing the need to tag each step individually. Defaults to\n * `\"race\"` mode.\n *\n * @example\n * ```ts\n * // Defaults to \"race\" mode\n * const winner = await group.parallel(async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * step.run(\"c\", () => \"c\"),\n * ]);\n * });\n *\n * // Or explicitly specify the mode\n * const winner = await group.parallel({ mode: \"race\" }, async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * ]);\n * });\n * ```\n */\n parallel: <T>(\n optionsOrCallback: ParallelOptions | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ) => Promise<T>;\n\n /**\n * Run an A/B experiment within a function. Selects a variant via a memoized\n * step, then executes the selected variant's callback at the top level so\n * its `step.*` calls go through normal step discovery.\n *\n * @example\n * ```ts\n * const result = await group.experiment(\"checkout-flow\", {\n * variants: {\n * control: () => step.run(\"control-checkout\", () => oldCheckout()),\n * new_flow: () => step.run(\"new-checkout\", () => newCheckout()),\n * },\n * select: Object.assign(() => \"control\", {\n * __experimentConfig: { strategy: \"weighted\", weights: { control: 80, new_flow: 20 } },\n * }),\n * });\n * ```\n */\n experiment: GroupExperiment;\n}\n\n/**\n * Dependencies injected into `createGroupTools` from the execution engine.\n */\nexport interface GroupToolsDeps {\n /**\n * A `step.run` variant with `opts.type = \"group.experiment\"`, extracted from\n * step tools via the experiment symbol. Undefined when not available.\n */\n // biome-ignore lint/suspicious/noExplicitAny: internal plumbing\n experimentStepRun?: (...args: any[]) => Promise<any>;\n}\n\n/**\n * Create the `group` tools object provided on the function execution context.\n *\n * @public\n */\nexport const createGroupTools = (deps?: GroupToolsDeps): GroupTools => {\n const experiment: GroupExperiment = (async (\n idOrOptions: StepOptionsOrId,\n // biome-ignore lint/suspicious/noExplicitAny: implementation signature for overloaded interface\n options: any,\n ) => {\n if (!deps?.experimentStepRun) {\n throw new Error(\n \"`group.experiment()` requires step tools to be available. \" +\n \"Ensure you are calling this within an Inngest function execution.\",\n );\n }\n\n const { variants, select, withVariant } = options;\n const variantNames = Object.keys(variants);\n\n if (variantNames.length === 0) {\n throw new Error(\n \"`group.experiment()` requires at least one variant to be defined.\",\n );\n }\n\n if (isALSFallback()) {\n throw new Error(\n \"`group.experiment()` requires AsyncLocalStorage support, which is not available in this runtime.\",\n );\n }\n\n const stepOpts = getStepOptions(idOrOptions);\n\n // Use the experiment step run to memoize the variant selection.\n // This creates a StepPlanned opcode with opts.type = \"group.experiment\".\n let experimentStepHashedId: string | undefined;\n\n const selectedVariant: string = await deps.experimentStepRun(\n idOrOptions,\n async () => {\n // Capture the hashed step ID so we can propagate it to variant sub-steps.\n experimentStepHashedId =\n getAsyncCtxSync()?.execution?.executingStep?.id;\n\n const alsInstance = await getAsyncLocalStorage();\n const currentCtx = getAsyncCtxSync()!;\n const selectCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution!,\n insideExperimentSelect: true,\n },\n };\n const result = await alsInstance.run(selectCtx, () =>\n select(variantNames),\n );\n\n if (!variantNames.includes(result)) {\n throw new NonRetriableError(\n `group.experiment(\"${stepOpts.id}\"): select() returned \"${result}\" ` +\n `which is not a known variant. Available variants: ${variantNames.join(\", \")}`,\n );\n }\n\n // Attach experiment metadata to this step's OutgoingOp.\n const ctx = getAsyncCtxSync();\n const execInstance = ctx?.execution?.instance;\n\n if (execInstance && experimentStepHashedId) {\n execInstance.addMetadata(\n experimentStepHashedId,\n \"inngest.experiment\",\n \"step\",\n \"merge\",\n {\n experiment_name: stepOpts.id,\n variant_selected: result,\n selection_strategy: select.__experimentConfig.strategy,\n available_variants: variantNames,\n ...(select.__experimentConfig.weights && {\n variant_weights: select.__experimentConfig.weights,\n }),\n } satisfies ExperimentMetadataValues,\n );\n\n if (select.__experimentConfig.nullishBucket) {\n execInstance.addMetadata(\n experimentStepHashedId,\n \"inngest.warnings\",\n \"step\",\n \"merge\",\n {\n message:\n \"experiment.bucket() received a null/undefined value; \" +\n 'hashing empty string \"\" for variant selection',\n },\n );\n }\n }\n\n return result;\n },\n );\n\n // Look up and execute the selected variant's callback at the top level\n // so its step.* calls go through normal step discovery.\n const variantFn = variants[selectedVariant];\n\n if (!variantFn) {\n throw new Error(\n `group.experiment(\"${stepOpts.id}\"): variant \"${selectedVariant}\" ` +\n `was selected but is not defined. Available variants: ${variantNames.join(\", \")}`,\n );\n }\n\n // Propagate experiment context via ALS so variant sub-steps include\n // experiment fields in their OutgoingOp.opts. The executor reads these\n // fields from opts and emits the step-scoped `inngest.experiment`\n // metadata span itself — the SDK does not need to call addMetadata()\n // for variant steps. See the companion executor change in inngest/inngest\n // for the server-side emission path.\n //\n // Also track whether any step tool is invoked to detect zero-step\n // variants.\n //\n // NOTE: experimentStepHashedId may be undefined on replay because it\n // is captured inside the selection step callback, which doesn't run\n // when memoized. We still set experimentContext (with an empty string\n // for the hashed ID fallback) so that variant sub-steps discovered on\n // replay still carry experiment fields in their opts and the executor\n // can attach metadata to their ClickHouse rows.\n const currentCtx = getAsyncCtxSync();\n const stepTracker = { found: false };\n let result: unknown;\n\n if (currentCtx?.execution && !isALSFallback()) {\n const als = await getAsyncLocalStorage();\n const nestedCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution,\n experimentContext: {\n experimentStepID: experimentStepHashedId ?? \"\",\n experimentName: stepOpts.id,\n variant: selectedVariant,\n selectionStrategy: select.__experimentConfig.strategy,\n },\n experimentStepTracker: stepTracker,\n },\n };\n result = await als.run(nestedCtx, () => variantFn());\n } else {\n result = await variantFn();\n }\n\n // If the variant returned without invoking any step tools, it will\n // silently re-execute on every replay. Throw a non-retriable error\n // to prevent this.\n if (!stepTracker.found && !isALSFallback()) {\n throw new NonRetriableError(\n `group.experiment(\"${stepOpts.id}\"): variant \"${selectedVariant}\" ` +\n \"did not invoke any step tools. Wrap your variant logic in \" +\n \"step.run() to ensure it is memoized and not re-executed on replay.\",\n );\n }\n\n if (withVariant) {\n return { result, variant: selectedVariant };\n }\n\n return result;\n }) as GroupExperiment;\n\n return { parallel, experiment };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"InngestGroupTools.cjs","names":["options: ParallelOptions","getAsyncCtxSync","getAsyncLocalStorage","isALSFallback","nestedCtx: AsyncContext","experiment: GroupExperiment","getStepOptions","experimentStepHashedId: string | undefined","selectedVariant: string","currentCtx","selectCtx: AsyncContext","result","NonRetriableError","result: unknown"],"sources":["../../src/components/InngestGroupTools.ts"],"sourcesContent":["import type { IsNever } from \"../helpers/types.ts\";\nimport type { StepOptionsOrId } from \"../types.ts\";\nimport {\n type AsyncContext,\n getAsyncCtxSync,\n getAsyncLocalStorage,\n isALSFallback,\n} from \"./execution/als.ts\";\nimport { getStepOptions } from \"./InngestStepTools.ts\";\nimport { NonRetriableError } from \"./NonRetriableError.ts\";\n\n/**\n * Options for the `group.parallel()` helper.\n */\nexport interface ParallelOptions {\n /**\n * The parallel mode to apply to all steps created within the callback.\n *\n * - `\"race\"`: Steps will be executed with race semantics, meaning the first\n * step to complete will \"win\" and remaining steps may be cancelled.\n */\n mode?: \"race\";\n}\n\n/**\n * A helper that sets the parallel mode for all steps created within the\n * callback. This allows you to use native `Promise.race()` with cleaner syntax.\n *\n * @example\n * ```ts\n * // Defaults to \"race\" mode\n * const winner = await group.parallel(async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * step.run(\"c\", () => \"c\"),\n * ]);\n * });\n *\n * // Or explicitly specify the mode\n * const winner = await group.parallel({ mode: \"race\" }, async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * ]);\n * });\n * ```\n */\nconst parallel = async <T>(\n optionsOrCallback: ParallelOptions | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n): Promise<T> => {\n const options: ParallelOptions =\n typeof optionsOrCallback === \"function\" ? {} : optionsOrCallback;\n const callback =\n typeof optionsOrCallback === \"function\" ? optionsOrCallback : maybeCallback;\n\n if (!callback) {\n throw new Error(\"`group.parallel()` requires a callback function\");\n }\n\n const currentCtx = getAsyncCtxSync();\n\n if (!currentCtx?.execution) {\n throw new Error(\n \"`group.parallel()` must be called within an Inngest function execution\",\n );\n }\n\n const als = await getAsyncLocalStorage();\n\n if (isALSFallback()) {\n throw new Error(\n \"`group.parallel()` requires AsyncLocalStorage support, which is not available in this runtime. \" +\n \"Workaround: Pass `parallelMode` directly to each step:\\n\" +\n ' step.run({ id: \"my-step\", parallelMode: \"race\" }, fn)',\n );\n }\n\n // Create a new context with the parallelMode set\n const nestedCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution,\n parallelMode: options.mode ?? \"race\",\n },\n };\n\n // Run the callback inside the nested context\n return als.run(nestedCtx, callback);\n};\n\n/**\n * Configuration for how the experiment selects a variant.\n */\nexport interface ExperimentStrategyConfig {\n strategy: string;\n weights?: Record<string, number>;\n nullishBucket?: boolean;\n}\n\n/**\n * A callable selection function that also carries strategy metadata.\n */\nexport interface ExperimentSelectFn {\n (variantNames?: string[]): Promise<string> | string;\n __experimentConfig: ExperimentStrategyConfig;\n}\n\n/**\n * Options for `group.experiment()`.\n */\nexport interface ExperimentOptions<\n TVariants extends Record<string, () => unknown>,\n> {\n /**\n * A map of variant names to callbacks. The selected variant's callback will\n * be executed at the top level so that any `step.*` calls inside it go\n * through normal step discovery.\n */\n variants: TVariants;\n\n /**\n * A selection function that returns the name of the variant to execute.\n * The result is memoized via a step so the same variant is used on retries.\n */\n select: ExperimentSelectFn;\n}\n\n/**\n * Options for `group.experiment()` when `withVariant` is true, which causes\n * the return type to include both the result and the selected variant name.\n */\nexport interface ExperimentOptionsWithVariant<\n TVariants extends Record<string, () => unknown>,\n> extends ExperimentOptions<TVariants> {\n /**\n * When true, the return value includes the variant name alongside the result.\n */\n withVariant: true;\n}\n\n/**\n * Computes the return type of an experiment based on variant callbacks.\n *\n * When `TConstraint` is `never`, the return type is inferred as the union of\n * all variant callback return types. Otherwise `TConstraint` is used directly.\n */\nexport type VariantResult<\n TConstraint,\n TVariants extends Record<string, () => unknown>,\n> = IsNever<TConstraint> extends true\n ? Awaited<ReturnType<TVariants[keyof TVariants]>>\n : TConstraint;\n\n/**\n * Metadata values stored alongside the experiment step for UI rendering.\n */\nexport interface ExperimentMetadataValues {\n experiment_name: string;\n variant: string;\n selection_strategy: string;\n available_variants: string[];\n variant_weights?: Record<string, number>;\n}\n\n/**\n * Overloaded interface for `group.experiment()`.\n */\nexport interface GroupExperiment {\n /**\n * Run an A/B experiment that selects and executes a variant. Returns both\n * the result and the selected variant name.\n */\n <TVariants extends Record<string, () => unknown>>(\n idOrOptions: StepOptionsOrId,\n options: ExperimentOptionsWithVariant<TVariants>,\n ): Promise<{\n result: VariantResult<never, TVariants>;\n variant: string;\n }>;\n\n /**\n * Run an A/B experiment that selects and executes a variant. Returns only\n * the variant callback's result.\n */\n <TVariants extends Record<string, () => unknown>>(\n idOrOptions: StepOptionsOrId,\n options: ExperimentOptions<TVariants>,\n ): Promise<VariantResult<never, TVariants>>;\n}\n\n/**\n * Tools for grouping and coordinating steps.\n *\n * @public\n */\nexport interface GroupTools {\n /**\n * Run a callback where all steps automatically receive a `parallelMode`\n * option, removing the need to tag each step individually. Defaults to\n * `\"race\"` mode.\n *\n * @example\n * ```ts\n * // Defaults to \"race\" mode\n * const winner = await group.parallel(async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * step.run(\"c\", () => \"c\"),\n * ]);\n * });\n *\n * // Or explicitly specify the mode\n * const winner = await group.parallel({ mode: \"race\" }, async () => {\n * return Promise.race([\n * step.run(\"a\", () => \"a\"),\n * step.run(\"b\", () => \"b\"),\n * ]);\n * });\n * ```\n */\n parallel: <T>(\n optionsOrCallback: ParallelOptions | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ) => Promise<T>;\n\n /**\n * Run an A/B experiment within a function. Selects a variant via a memoized\n * step, then executes the selected variant's callback at the top level so\n * its `step.*` calls go through normal step discovery.\n *\n * @example\n * ```ts\n * const result = await group.experiment(\"checkout-flow\", {\n * variants: {\n * control: () => step.run(\"control-checkout\", () => oldCheckout()),\n * new_flow: () => step.run(\"new-checkout\", () => newCheckout()),\n * },\n * select: Object.assign(() => \"control\", {\n * __experimentConfig: { strategy: \"weighted\", weights: { control: 80, new_flow: 20 } },\n * }),\n * });\n * ```\n */\n experiment: GroupExperiment;\n}\n\n/**\n * Dependencies injected into `createGroupTools` from the execution engine.\n */\nexport interface GroupToolsDeps {\n /**\n * A `step.run` variant with `opts.type = \"group.experiment\"`, extracted from\n * step tools via the experiment symbol. Undefined when not available.\n */\n // biome-ignore lint/suspicious/noExplicitAny: internal plumbing\n experimentStepRun?: (...args: any[]) => Promise<any>;\n}\n\n/**\n * Create the `group` tools object provided on the function execution context.\n *\n * @public\n */\nexport const createGroupTools = (deps?: GroupToolsDeps): GroupTools => {\n const experiment: GroupExperiment = (async (\n idOrOptions: StepOptionsOrId,\n // biome-ignore lint/suspicious/noExplicitAny: implementation signature for overloaded interface\n options: any,\n ) => {\n if (!deps?.experimentStepRun) {\n throw new Error(\n \"`group.experiment()` requires step tools to be available. \" +\n \"Ensure you are calling this within an Inngest function execution.\",\n );\n }\n\n const { variants, select, withVariant } = options;\n const variantNames = Object.keys(variants);\n\n if (variantNames.length === 0) {\n throw new Error(\n \"`group.experiment()` requires at least one variant to be defined.\",\n );\n }\n\n if (isALSFallback()) {\n throw new Error(\n \"`group.experiment()` requires AsyncLocalStorage support, which is not available in this runtime.\",\n );\n }\n\n const stepOpts = getStepOptions(idOrOptions);\n\n // Use the experiment step run to memoize the variant selection.\n // This creates a StepPlanned opcode with opts.type = \"group.experiment\".\n let experimentStepHashedId: string | undefined;\n\n const selectedVariant: string = await deps.experimentStepRun(\n idOrOptions,\n async () => {\n // Capture the hashed step ID so we can propagate it to variant sub-steps.\n experimentStepHashedId =\n getAsyncCtxSync()?.execution?.executingStep?.id;\n\n const alsInstance = await getAsyncLocalStorage();\n const currentCtx = getAsyncCtxSync()!;\n const selectCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution!,\n insideExperimentSelect: true,\n },\n };\n const result = await alsInstance.run(selectCtx, () =>\n select(variantNames),\n );\n\n if (!variantNames.includes(result)) {\n throw new NonRetriableError(\n `group.experiment(\"${stepOpts.id}\"): select() returned \"${result}\" ` +\n `which is not a known variant. Available variants: ${variantNames.join(\", \")}`,\n );\n }\n\n // Attach experiment metadata to this step's OutgoingOp.\n const ctx = getAsyncCtxSync();\n const execInstance = ctx?.execution?.instance;\n\n if (execInstance && experimentStepHashedId) {\n execInstance.addMetadata(\n experimentStepHashedId,\n \"inngest.experiment\",\n \"step\",\n \"merge\",\n {\n experiment_name: stepOpts.id,\n variant: result,\n selection_strategy: select.__experimentConfig.strategy,\n available_variants: variantNames,\n ...(select.__experimentConfig.weights && {\n variant_weights: select.__experimentConfig.weights,\n }),\n } satisfies ExperimentMetadataValues,\n );\n\n if (select.__experimentConfig.nullishBucket) {\n execInstance.addMetadata(\n experimentStepHashedId,\n \"inngest.warnings\",\n \"step\",\n \"merge\",\n {\n message:\n \"experiment.bucket() received a null/undefined value; \" +\n 'hashing empty string \"\" for variant selection',\n },\n );\n }\n }\n\n return result;\n },\n );\n\n // Look up and execute the selected variant's callback at the top level\n // so its step.* calls go through normal step discovery.\n const variantFn = variants[selectedVariant];\n\n if (!variantFn) {\n throw new Error(\n `group.experiment(\"${stepOpts.id}\"): variant \"${selectedVariant}\" ` +\n `was selected but is not defined. Available variants: ${variantNames.join(\", \")}`,\n );\n }\n\n // Propagate experiment context via ALS so variant sub-steps include\n // experiment fields in their OutgoingOp.opts. The executor reads these\n // fields from opts and emits the step-scoped `inngest.experiment`\n // metadata span itself — the SDK does not need to call addMetadata()\n // for variant steps. See the companion executor change in inngest/inngest\n // for the server-side emission path.\n //\n // Also track whether any step tool is invoked to detect zero-step\n // variants.\n //\n // NOTE: experimentStepHashedId may be undefined on replay because it\n // is captured inside the selection step callback, which doesn't run\n // when memoized. We still set experimentContext (with an empty string\n // for the hashed ID fallback) so that variant sub-steps discovered on\n // replay still carry experiment fields in their opts and the executor\n // can attach metadata to their ClickHouse rows.\n const currentCtx = getAsyncCtxSync();\n const stepTracker = { found: false };\n let result: unknown;\n\n if (currentCtx?.execution && !isALSFallback()) {\n const als = await getAsyncLocalStorage();\n const nestedCtx: AsyncContext = {\n ...currentCtx,\n execution: {\n ...currentCtx.execution,\n experimentContext: {\n experimentStepID: experimentStepHashedId ?? \"\",\n experimentName: stepOpts.id,\n variant: selectedVariant,\n selectionStrategy: select.__experimentConfig.strategy,\n },\n experimentStepTracker: stepTracker,\n },\n };\n result = await als.run(nestedCtx, () => variantFn());\n } else {\n result = await variantFn();\n }\n\n // If the variant returned without invoking any step tools, it will\n // silently re-execute on every replay. Throw a non-retriable error\n // to prevent this.\n if (!stepTracker.found && !isALSFallback()) {\n throw new NonRetriableError(\n `group.experiment(\"${stepOpts.id}\"): variant \"${selectedVariant}\" ` +\n \"did not invoke any step tools. Wrap your variant logic in \" +\n \"step.run() to ensure it is memoized and not re-executed on replay.\",\n );\n }\n\n if (withVariant) {\n return { result, variant: selectedVariant };\n }\n\n return result;\n }) as GroupExperiment;\n\n return { parallel, experiment };\n};\n"],"mappings":"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"}
@@ -75,7 +75,7 @@ const createGroupTools = (deps) => {
75
75
  if (execInstance && experimentStepHashedId) {
76
76
  execInstance.addMetadata(experimentStepHashedId, "inngest.experiment", "step", "merge", {
77
77
  experiment_name: stepOpts.id,
78
- variant_selected: result$1,
78
+ variant: result$1,
79
79
  selection_strategy: select.__experimentConfig.strategy,
80
80
  available_variants: variantNames,
81
81
  ...select.__experimentConfig.weights && { variant_weights: select.__experimentConfig.weights }