From 8402f46970c007bab9e0f1f6ae653d955650d503 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 21 Dec 2023 14:41:58 +0100 Subject: [PATCH] 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 }) ``` --- .changeset/hip-turtles-smell.md | 5 +++ packages/workflows-sdk/package.json | 3 +- packages/workflows-sdk/src/utils/_test.ts | 27 ++++++++++++++++ .../src/utils/composer/create-step.ts | 32 +++++++++++-------- .../workflows-sdk/src/utils/composer/type.ts | 27 ++++++++++++---- 5 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 .changeset/hip-turtles-smell.md create mode 100644 packages/workflows-sdk/src/utils/_test.ts diff --git a/.changeset/hip-turtles-smell.md b/.changeset/hip-turtles-smell.md new file mode 100644 index 0000000000..147e6cd877 --- /dev/null +++ b/.changeset/hip-turtles-smell.md @@ -0,0 +1,5 @@ +--- +"@medusajs/workflows-sdk": patch +--- + +feat(workflows-sdk): Allow a step to not define an expected input diff --git a/packages/workflows-sdk/package.json b/packages/workflows-sdk/package.json index 7c64f4d1be..42749029ef 100644 --- a/packages/workflows-sdk/package.json +++ b/packages/workflows-sdk/package.json @@ -39,6 +39,7 @@ "prepublishOnly": "cross-env NODE_ENV=production tsc --build", "build": "rimraf dist && tsc --build", "watch": "tsc --build --watch", - "test": "jest --runInBand --bail --forceExit" + "test": "jest --runInBand --bail --forceExit", + "test:run": "../../node_modules/.bin/ts-node ./src/utils/_test.ts" } } diff --git a/packages/workflows-sdk/src/utils/_test.ts b/packages/workflows-sdk/src/utils/_test.ts new file mode 100644 index 0000000000..eca106c9ee --- /dev/null +++ b/packages/workflows-sdk/src/utils/_test.ts @@ -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" } + }) diff --git a/packages/workflows-sdk/src/utils/composer/create-step.ts b/packages/workflows-sdk/src/utils/composer/create-step.ts index 78e47f6933..9a7edabd6f 100644 --- a/packages/workflows-sdk/src/utils/composer/create-step.ts +++ b/packages/workflows-sdk/src/utils/composer/create-step.ts @@ -19,13 +19,11 @@ import { isString, OrchestrationUtils } from "@medusajs/utils" * * @returns The expected output based on the type parameter `TOutput`. */ -type InvokeFn = ( +type InvokeFn = ( /** * 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 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 }, @@ -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 = 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 - }): WorkflowData { + const returnFn = function ( + input: + | { + [K in keyof TInvokeInput]: WorkflowData + } + | undefined + ): WorkflowData { 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 returnFn.__type = OrchestrationUtils.SymbolWorkflowStepBind returnFn.__step__ = stepName - return returnFn as unknown as StepFunction + return returnFn } diff --git a/packages/workflows-sdk/src/utils/composer/type.ts b/packages/workflows-sdk/src/utils/composer/type.ts index 14c0d8396e..003458a379 100644 --- a/packages/workflows-sdk/src/utils/composer/type.ts +++ b/packages/workflows-sdk/src/utils/composer/type.ts @@ -18,8 +18,24 @@ export type StepFunctionResult = * @typeParam TInput - The type of the input of the step. * @typeParam TOutput - The type of the output of the step. */ -export type StepFunction = { - (input: { [K in keyof TInput]: WorkflowData }): WorkflowData<{ +export type StepFunction = (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 } + : WorkflowData + ): WorkflowData<{ + [K in keyof TOutput]: TOutput[K] + }> + }) & + WorkflowDataProperties<{ [K in keyof TOutput]: TOutput[K] }> & { config( @@ -27,10 +43,9 @@ export type StepFunction = { ): WorkflowData<{ [K in keyof TOutput]: TOutput[K] }> - } -} & WorkflowDataProperties<{ - [K in keyof TOutput]: TOutput[K] -}> + } & WorkflowDataProperties<{ + [K in keyof TOutput]: TOutput[K] + }> export type WorkflowDataProperties = { __type: Symbol