feat(workflows-sdk): Allow a step to not define an expected input (#5775)

**What**
Allow a step to not define an expected input, previously even if no input was expected, an object was always expected to be passed to the stepFunction inside the workflow composition. Now
```ts
const stepWithoutArgs = createStep("step1", () => {
  return new StepResponse("string")
})

const stepWithoutExepectedInput = createStep("step2", (_: {}, context) => {
  console.log("input", _) // {}
  return new StepResponse("string")
})

const workflow = createWorkflow("workflow1", () => {
  stepWithoutArgs()
  return stepWithoutExepectedInput()
})

workflow()
  .run()
  .then((res) => {
    console.log(res.result) // string
  })
```
This commit is contained in:
Adrien de Peretti
2023-12-21 13:41:58 +00:00
committed by GitHub
parent 890e76a5c5
commit 8402f46970
5 changed files with 73 additions and 21 deletions
+27
View File
@@ -0,0 +1,27 @@
import { createStep, createWorkflow, StepResponse } from "./composer"
const step1 = createStep("step1", async (input: {}, context) => {
console.log("step1", input) // Here the input will be `{}` and the createWorkflow does not have to provide an input
return new StepResponse({ step1: "step1" })
})
const step2 = createStep("step2", async (input: string, context) => {
console.log("step2", input) // Here the input will be the string value `step1`
return new StepResponse({ step2: "step2" })
})
const step3 = createStep("step3", async () => {
return new StepResponse({ step3: "step3" })
})
const workflow = createWorkflow("workflow", function () {
const step1Res = step1()
step3()
return step2(step1Res.step1)
})
workflow()
.run({})
.then((res) => {
console.log(res.result) // result: { step2: "step2" }
})
@@ -19,13 +19,11 @@ import { isString, OrchestrationUtils } from "@medusajs/utils"
*
* @returns The expected output based on the type parameter `TOutput`.
*/
type InvokeFn<TInput extends object, TOutput, TCompensateInput> = (
type InvokeFn<TInput, TOutput, TCompensateInput> = (
/**
* The input of the step.
*/
input: {
[Key in keyof TInput]: TInput[Key]
},
input: TInput,
/**
* The step's context.
*/
@@ -64,13 +62,13 @@ interface ApplyStepOptions<
TStepInputs extends {
[K in keyof TInvokeInput]: WorkflowData<TInvokeInput[K]>
},
TInvokeInput extends object,
TInvokeInput,
TInvokeResultOutput,
TInvokeResultCompensateInput
> {
stepName: string
stepConfig?: TransactionStepsDefinition
input: TStepInputs
input?: TStepInputs
invokeFn: InvokeFn<
TInvokeInput,
TInvokeResultOutput,
@@ -92,7 +90,7 @@ interface ApplyStepOptions<
* @param compensateFn
*/
function applyStep<
TInvokeInput extends object,
TInvokeInput,
TStepInput extends {
[K in keyof TInvokeInput]: WorkflowData<TInvokeInput[K]>
},
@@ -125,7 +123,9 @@ function applyStep<
context: transactionContext.context,
}
const argInput = await resolveValue(input, transactionContext)
const argInput = input
? await resolveValue(input, transactionContext)
: {}
const stepResponse: StepResponse<any, any> = await invokeFn.apply(
this,
[argInput, executionContext]
@@ -236,7 +236,7 @@ function applyStep<
* )
*/
export function createStep<
TInvokeInput extends object,
TInvokeInput,
TInvokeResultOutput,
TInvokeResultCompensateInput
>(
@@ -267,9 +267,13 @@ export function createStep<
(isString(nameOrConfig) ? nameOrConfig : nameOrConfig.name) ?? invokeFn.name
const config = isString(nameOrConfig) ? {} : nameOrConfig
const returnFn = function (input: {
[K in keyof TInvokeInput]: WorkflowData<TInvokeInput[K]>
}): WorkflowData<TInvokeResultOutput> {
const returnFn = function (
input:
| {
[K in keyof TInvokeInput]: WorkflowData<TInvokeInput[K]>
}
| undefined
): WorkflowData<TInvokeResultOutput> {
if (!global[OrchestrationUtils.SymbolMedusaWorkflowComposerContext]) {
throw new Error(
"createStep must be used inside a createWorkflow definition"
@@ -296,10 +300,10 @@ export function createStep<
compensateFn,
})
)
}
} as StepFunction<TInvokeInput, TInvokeResultOutput>
returnFn.__type = OrchestrationUtils.SymbolWorkflowStepBind
returnFn.__step__ = stepName
return returnFn as unknown as StepFunction<TInvokeInput, TInvokeResultOutput>
return returnFn
}
@@ -18,8 +18,24 @@ export type StepFunctionResult<TOutput extends unknown | unknown[] = unknown> =
* @typeParam TInput - The type of the input of the step.
* @typeParam TOutput - The type of the output of the step.
*/
export type StepFunction<TInput extends object = object, TOutput = unknown> = {
(input: { [K in keyof TInput]: WorkflowData<TInput[K]> }): WorkflowData<{
export type StepFunction<TInput, TOutput = unknown> = (keyof TInput extends []
? // Function that doesn't expect any input
{
(): WorkflowData<{
[K in keyof TOutput]: TOutput[K]
}>
}
: // function that expects an input object
{
(
input: TInput extends object
? { [K in keyof TInput]: WorkflowData<TInput[K]> }
: WorkflowData<TInput>
): WorkflowData<{
[K in keyof TOutput]: TOutput[K]
}>
}) &
WorkflowDataProperties<{
[K in keyof TOutput]: TOutput[K]
}> & {
config(
@@ -27,10 +43,9 @@ export type StepFunction<TInput extends object = object, TOutput = unknown> = {
): WorkflowData<{
[K in keyof TOutput]: TOutput[K]
}>
}
} & WorkflowDataProperties<{
[K in keyof TOutput]: TOutput[K]
}>
} & WorkflowDataProperties<{
[K in keyof TOutput]: TOutput[K]
}>
export type WorkflowDataProperties<T = unknown> = {
__type: Symbol