Files
medusa-store/packages/workflows-sdk/src/utils/composer/transform.ts
Adrien de Peretti 9cc787cac4 feat(workflows-sdk): Configurable retries upon step creation (#5728)
**What**
- Allow to create step that can be configured to have a max retry
- Step end retry mechanism on permanent failure

Also added an API to override a step configuration from within the createWorkflow
```ts
const step = createStep({ name: "step", maxRetries: 3 }, async (_, context) => {
  return new StepResponse({ output: "output" })
})

const workflow = createWorkflow("workflow", function () {
  const res = step().config({ maxRetries: 5 }) // This will override the original maxRetries of 3
})
```

**NOTE**
We can maybe find another name than config on the step workflow data to override the step config.
2023-12-19 09:38:27 +00:00

195 lines
5.7 KiB
TypeScript

import { resolveValue } from "./helpers"
import { StepExecutionContext, WorkflowData } from "./type"
import { proxify } from "./helpers/proxy"
import { OrchestrationUtils } from "@medusajs/utils"
type Func1<T extends object | WorkflowData, U> = (
input: T extends WorkflowData<infer U>
? U
: T extends object
? { [K in keyof T]: T[K] extends WorkflowData<infer U> ? U : T[K] }
: {},
context: StepExecutionContext
) => U | Promise<U>
type Func<T, U> = (input: T, context: StepExecutionContext) => U | Promise<U>
/**
*
* This function transforms the output of other utility functions.
*
* For example, if you're using the value(s) of some step(s) as an input to a later step. As you can't directly manipulate data in the workflow constructor function passed to {@link createWorkflow},
* the `transform` function provides access to the runtime value of the step(s) output so that you can manipulate them.
*
* Another example is if you're using the runtime value of some step(s) as the output of a workflow.
*
* If you're also retrieving the output of a hook and want to check if its value is set, you must use a workflow to get the runtime value of that hook.
*
* @returns There's no expected value to be returned by the `transform` function.
*
* @example
* import {
* createWorkflow,
* transform
* } from "@medusajs/workflows-sdk"
* import { step1, step2 } from "./steps"
*
* type WorkflowInput = {
* name: string
* }
*
* type WorkflowOutput = {
* message: string
* }
*
* const myWorkflow = createWorkflow<
* WorkflowInput,
* WorkflowOutput
* >
* ("hello-world", (input) => {
* const str1 = step1(input)
* const str2 = step2(input)
*
* return transform({
* str1,
* str2
* }, (input) => ({
* message: `${input.str1}${input.str2}`
* }))
* })
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RFinal>(
/**
* The output(s) of other step functions.
*/
values: T,
/**
* The transform function used to perform action on the runtime values of the provided `values`.
*/
...func:
| [Func1<T, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RB, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RB, RC, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RB, RC, RD, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RB, RC, RD, RE, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RE>, Func<RE, RFinal>]
): WorkflowData<RFinal>
/**
* @internal
*/
// prettier-ignore
// eslint-disable-next-line max-len
export function transform<T extends object | WorkflowData, RA, RB, RC, RD, RE, RF, RFinal>(
values: T,
...func:
| [Func1<T, RFinal>]
| [Func1<T, RA>, Func<RA, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RE>, Func<RE, RFinal>]
| [Func1<T, RA>, Func<RA, RB>, Func<RB, RC>, Func<RC, RD>, Func<RD, RE>, Func<RE, RF>, Func<RF, RFinal>]
): WorkflowData<RFinal>
export function transform(
values: any | any[],
...functions: Function[]
): unknown {
const ret = {
__type: OrchestrationUtils.SymbolWorkflowStepTransformer,
__resolver: undefined,
}
const returnFn = async function (transactionContext): Promise<any> {
const allValues = await resolveValue(values, transactionContext)
const stepValue = allValues
? JSON.parse(JSON.stringify(allValues))
: allValues
let finalResult
for (let i = 0; i < functions.length; i++) {
const fn = functions[i]
const arg = i === 0 ? stepValue : finalResult
finalResult = await fn.apply(fn, [arg, transactionContext])
}
return finalResult
}
const proxyfiedRet = proxify<WorkflowData & { __resolver: any }>(
ret as unknown as WorkflowData
)
proxyfiedRet.__resolver = returnFn as any
return proxyfiedRet
}