Merge branch 'develop' into docs/revise-recipe-examples

This commit is contained in:
Shahed Nasser
2024-12-11 12:41:02 +02:00
22 changed files with 328 additions and 155 deletions
@@ -185,7 +185,7 @@ Add the `validateAndTransformQuery` middleware to the API route in the file `src
```ts title="src/api/middlewares.ts"
import {
validateAndTransformQuery,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { PostStoreCustomSchema } from "./custom/validators"
@@ -300,7 +300,7 @@ The first step is to use the `validateAndTransformQuery` middleware on the `GET`
```ts title="src/api/middlewares.ts"
import {
validateAndTransformQuery,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { createFindParams } from "@medusajs/medusa/api/utils/validators"
@@ -105,7 +105,7 @@ export const syncBrandsWorkflow = createWorkflow(
() => {
const brands = retrieveBrandsStep()
updateBrandsInCmsStep({ brands })
createBrandsInCmsStep({ brands })
}
)
```
@@ -8,19 +8,17 @@ In this chapter, you'll learn how to execute an action based on a condition in a
## Why If-Conditions Aren't Allowed in Workflows?
Medusa creates an internal representation of the workflow definition you pass to `createWorkflow` to track and store its steps.
At that point, variables in the workflow don't have any values. They only do when you execute the workflow.
Medusa creates an internal representation of the workflow definition you pass to `createWorkflow` to track and store its steps. At that point, variables in the workflow don't have any values. They only do when you execute the workflow.
So, you can't use an if-condition that checks a variable's value, as the condition will be evaluated when Medusa creates the internal representation of the workflow, rather than during execution.
Instead, use when-then from the Workflows SDK.
Instead, use when-then from the Workflows SDK. It allows you to perform steps in a workflow only if a condition that you specify is satisified.
---
## What is the When-Then Utility?
## How to use When-Then?
when-then from the Workflows SDK executes an action if a condition is satisfied. The `when` function accepts as a parameter a function that returns a boolean value, and the `then` function is chained to `when`. `then` accepts as a parameter a function that's executed if `when`'s parameter function returns a `true` value.
The Workflows SDK provides a `when` function that is used to check whether a condition is true. You chain a `then` function to `when` that specifies the steps to execute if the condition in `when` is satisfied.
For example:
@@ -77,4 +75,101 @@ In this code snippet, you execute the `isActiveStep` only if the `input.is_activ
To specify the action to perform if the condition is satisfied, chain a `then` function to `when` and pass it a callback function.
The callback function is only executed if `when`'s second parameter function returns a `true` value.
The callback function is only executed if `when`'s second parameter function returns a `true` value.
---
## Implementing If-Else with When-Then
when-then doesn't support if-else conditions. Instead, use two `when-then` conditions in your workflow.
For example:
export const ifElseHighlights = [
["7", "when", "This when-then block acts as an if condition."],
["16", "when", "This when-then block acts as an else condiiton."]
]
```ts highlights={ifElseHighlights}
const workflow = createWorkflow(
"workflow",
function (input: {
is_active: boolean
}) {
const isActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return isActiveStep()
})
const notIsActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return notIsActiveStep()
})
// ...
}
)
```
In the above workflow, you use two `when-then` blocks. The first one performs a step if `input.is_active` is `true`, and the second performs a step if `input.is_active` is `false`, acting as an else condition.
---
## Specify Name for When-Then
Internally, `when-then` blocks have a unique name similar to a step. When you return a step's result in a `when-then` block, the block's name is derived from the step's name. For example:
```ts
const isActiveResult = when(
input,
(input) => {
return input.is_active
}
).then(() => {
return isActiveStep()
})
```
This `when-then` block's internal name will be `when-then-is-active`, where `is-active` is the step's name.
However, if you need to return in your `when-then` block something other than a step's result, you need to specify a unique step name for that block. Otherwise, Medusa will generate a random name for it which can cause unexpected errors in production.
You pass a name for `when-then` as a first parameter of `when`, whose signature can accept three parameters in this case. For example:
export const nameHighlights = [
["2", `"check-is-active"`, "The when-then block's name."],
["10", "return", "`then` returns a value other than the step's result."]
]
```ts highlights={nameHighlights}
const { isActive } = when(
"check-is-active",
input,
(input) => {
return input.is_active
}
).then(() => {
const isActive = isActiveStep()
return {
isActive,
}
})
```
Since `then` returns a value different than the step's result, you pass to the `when` function the following parameters:
1. A unique name to be assigned to the `when-then` block.
2. Either an object or the workflow's input. This data is passed as a parameter to the function in `when`'s second parameter.
3. A function that returns a boolean indicating whether to execute the action in `then`.
The second and third parameters are the same as the parameters you previously passed to `when`.
@@ -157,6 +157,8 @@ const myWorkflow = createWorkflow(
})
```
You can also pair multiple `when-then` blocks to implement an `if-else` condition as explained in [this chapter](../conditions/page.mdx).
### No Conditional Operators
You can't use conditional operators in a workflow, such as `??` or `||`.
+2 -2
View File
@@ -32,11 +32,11 @@ export const generatedEditDates = {
"app/learn/fundamentals/data-models/default-properties/page.mdx": "2024-10-21T13:30:21.368Z",
"app/learn/fundamentals/workflows/advanced-example/page.mdx": "2024-09-11T10:46:59.975Z",
"app/learn/fundamentals/events-and-subscribers/emit-event/page.mdx": "2024-11-25T16:19:32.168Z",
"app/learn/fundamentals/workflows/conditions/page.mdx": "2024-12-09T15:55:51.565Z",
"app/learn/fundamentals/workflows/conditions/page.mdx": "2024-12-11T08:44:00.239Z",
"app/learn/fundamentals/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00",
"app/learn/fundamentals/admin/page.mdx": "2024-10-23T07:08:55.898Z",
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2024-12-04T07:37:59.822Z",
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-09T14:43:35.160Z",
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-11T08:36:08.282Z",
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2024-11-11T15:27:59.794Z",
"app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2024-10-28T04:22:21.328Z",
"app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
@@ -529,12 +529,15 @@ In the workflow, you retrieve the cart's linked `Custom` record using Query.
Next, replace the `TODO` with the following:
```ts title="src/workflows/update-custom-from-cart/index.ts"
const created = when({
input,
carts,
}, (data) =>
!data.carts[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-cart-custom-link",
{
input,
carts,
},
(data) =>
!data.carts[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
@@ -563,14 +566,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:
```ts title="src/workflows/update-custom-from-cart/index.ts"
const deleted = when({
input,
carts,
}, (data) =>
data.carts[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-cart-custom-link",
{
input,
carts,
}, (data) =>
data.carts[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
@@ -599,12 +604,10 @@ const updated = when({
carts,
}, (data) => data.carts[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: carts[0].custom.id,
custom_name: input.additional_data.custom_name,
})
return custom
})
return new WorkflowResponse({
@@ -541,12 +541,14 @@ In the workflow, you retrieve the customer's linked `Custom` record using Query.
Next, replace the `TODO` with the following:
```ts title="src/workflows/update-custom-from-customer/index.ts"
const created = when({
input,
customers,
}, (data) =>
!data.customers[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-customer-custom-link",
{
input,
customers,
}, (data) =>
!data.customers[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
@@ -575,14 +577,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:
```ts title="src/workflows/update-custom-from-customer/index.ts"
const deleted = when({
input,
customers,
}, (data) =>
data.customers[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-customer-custom-link",
{
input,
customers,
}, (data) =>
data.customers[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
@@ -611,12 +615,10 @@ const updated = when({
customers,
}, (data) => data.customers[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: customers[0].custom.id,
custom_name: input.additional_data.custom_name,
})
return custom
})
return new WorkflowResponse({
@@ -547,12 +547,14 @@ In the workflow, you retrieve the product's linked `Custom` record using Query.
Next, replace the `TODO` with the following:
```ts title="src/workflows/update-custom-from-product/index.ts"
const created = when({
input,
products,
}, (data) =>
!data.products[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-product-custom-link",
{
input,
products,
}, (data) =>
!data.products[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
@@ -581,14 +583,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:
```ts title="src/workflows/update-custom-from-product/index.ts"
const deleted = when({
input,
products,
}, (data) =>
data.products[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-product-custom-link",
{
input,
products,
}, (data) =>
data.products[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
@@ -617,12 +621,10 @@ const updated = when({
products,
}, (data) => data.products[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: products[0].custom.id,
custom_name: input.additional_data.custom_name,
})
return custom
})
return new WorkflowResponse({
@@ -553,12 +553,14 @@ In the workflow, you retrieve the promotion's linked `Custom` record using Query
Next, replace the `TODO` with the following:
```ts title="src/workflows/update-custom-from-promotion/index.ts"
const created = when({
input,
promotions,
}, (data) =>
!data.promotions[0].custom &&
data.input.additional_data?.custom_name?.length > 0
const created = when(
"create-promotion-custom-link",
{
input,
promotions,
}, (data) =>
!data.promotions[0].custom &&
data.input.additional_data?.custom_name?.length > 0
)
.then(() => {
const custom = createCustomStep({
@@ -587,14 +589,16 @@ To create the `Custom` record, you use the `createCustomStep` you created in an
Next, replace the new `TODO` with the following:
```ts title="src/workflows/update-custom-from-promotion/index.ts"
const deleted = when({
input,
promotions,
}, (data) =>
data.promotions[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
const deleted = when(
"delete-promotion-custom-link",
{
input,
promotions,
}, (data) =>
data.promotions[0].custom && (
data.input.additional_data?.custom_name === null ||
data.input.additional_data?.custom_name.length === 0
)
)
.then(() => {
deleteCustomStep({
@@ -623,12 +627,10 @@ const updated = when({
promotions,
}, (data) => data.promotions[0].custom && data.input.additional_data?.custom_name?.length > 0)
.then(() => {
const custom = updateCustomStep({
return updateCustomStep({
id: promotions[0].custom.id,
custom_name: input.additional_data.custom_name,
})
return custom
})
return new WorkflowResponse({
+3 -4
View File
@@ -334,7 +334,7 @@ export const PostStoreCustomSchema = z.object({
```ts title="src/api/middlewares.ts" highlights={[["13", "validateAndTransformBody"]]}
import {
validateAndTransformBody,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { PostStoreCustomSchema } from "./custom/validators"
@@ -629,7 +629,7 @@ import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
defineMiddlewares
defineMiddlewares,
} from "@medusajs/framework/http"
import { ConfigModule } from "@medusajs/framework/types"
import { parseCorsOrigins } from "@medusajs/framework/utils"
@@ -2296,8 +2296,7 @@ const workflow = createWorkflow(
return input.is_active
}
).then(() => {
const stepResult = isActiveStep()
return stepResult
return isActiveStep()
})
// executed without condition
@@ -695,17 +695,17 @@ export const syncStep = createStep(
const sanityModule: SanityModuleService = container.resolve(SANITY_MODULE)
const query = container.resolve(ContainerRegistrationKeys.QUERY)
let total = 0;
const total = 0
const upsertMap: {
before: any
after: any
}[] = []
const batchSize = 200;
let hasMore = true;
let offset = 0;
let filters = input.product_ids ? {
id: input.product_ids
const batchSize = 200
const hasMore = true
const offset = 0
const filters = input.product_ids ? {
id: input.product_ids,
} : {}
while (hasMore) {
@@ -772,16 +772,16 @@ while (hasMore) {
const after = await sanityModule.upsertSyncDocument(
"product",
prod as ProductDTO
);
)
upsertMap.push({
// @ts-ignore
before: prod.sanity_product,
after
after,
})
return after
}),
})
)
} catch (e) {
return StepResponse.permanentFailure(
@@ -805,7 +805,7 @@ You also wrap the `promiseAll` function within a try-catch block. In the catch b
Finally, after the `while` loop and at the end of the step, add the following return statement:
```ts title="src/workflows/sanity-sync-products/steps/sync.ts"
return new StepResponse({ total }, upsertMap);
return new StepResponse({ total }, upsertMap)
```
If no errors occur, the step returns an instance of `StepResponse`, which must be returned by any step. It accepts as a first parameter the data to return to the workflow that executed this step.
@@ -440,7 +440,7 @@ export const validateVariantOutOfStockStep = createStep(
const query = container.resolve("query")
const availability = await getVariantAvailability(query, {
variant_ids: [variant_id],
sales_channel_id
sales_channel_id,
})
if (availability[variant_id].availability > 0) {
@@ -599,7 +599,7 @@ export const subscriptionWorkflow1Highlights = [
["16", "createWorkflow", "Create a workflow."],
["23", "transform", "Set the customer ID to an empty string if not provided."],
["28", "when", "If email is not set, try to retrieve customer by its ID."],
["44", "transform", "Set the email either to the one in the input or the specified customer's email."],
["48", "transform", "Set the email either to the one in the input or the specified customer's email."],
]
```ts title="src/workflows/create-restock-subscription/index.ts" highlights={subscriptionWorkflow1Highlights}
@@ -623,24 +623,28 @@ export const createRestockSubscriptionWorkflow = createWorkflow(
({
variant_id,
sales_channel_id,
customer
customer,
}: CreateRestockSubscriptionWorkflowInput) => {
const customerId = transform({
customer
customer,
}, (data) => {
return data.customer.customer_id || ""
})
const retrievedCustomer = when({ customer }, ({ customer }) => {
return !customer.email
}).then(() => {
const retrievedCustomer = when(
"retrieve-customer-by-id",
{ customer },
({ customer }) => {
return !customer.email
}
).then(() => {
// @ts-ignore
const { data } = useQueryGraphStep({
entity: "customer",
fields: ["email"],
filters: { id: customerId },
options: {
throwIfKeyNotFound: true
}
throwIfKeyNotFound: true,
},
}).config({ name: "retrieve-customer" })
return data
@@ -648,7 +652,7 @@ export const createRestockSubscriptionWorkflow = createWorkflow(
const email = transform({
retrievedCustomer,
customer
customer,
}, (data) => {
return data.customer?.email ?? data.retrievedCustomer?.[0].email
})
@@ -688,7 +692,7 @@ export const subscriptionWorkflow2Highlights = [
```ts title="src/workflows/create-restock-subscription/index.ts" highlights={subscriptionWorkflow2Highlights}
validateVariantOutOfStockStep({
variant_id,
sales_channel_id
sales_channel_id,
})
// @ts-ignore
@@ -698,8 +702,8 @@ const { data: restockSubscriptions } = useQueryGraphStep({
filters: {
email,
variant_id,
sales_channel_id
}
sales_channel_id,
},
}).config({ name: "retrieve-subscriptions" })
when({ restockSubscriptions }, ({ restockSubscriptions }) => {
@@ -710,7 +714,7 @@ when({ restockSubscriptions }, ({ restockSubscriptions }) => {
variant_id,
sales_channel_id,
email,
customer_id: customer.customer_id
customer_id: customer.customer_id,
})
})
@@ -720,7 +724,7 @@ when({ restockSubscriptions }, ({ restockSubscriptions }) => {
.then(() => {
updateRestockSubscriptionStep({
id: restockSubscriptions[0].id,
customer_id: customer.customer_id
customer_id: customer.customer_id,
})
})
@@ -731,8 +735,8 @@ const { data: restockSubscription } = useQueryGraphStep({
filters: {
email,
variant_id,
sales_channel_id
}
sales_channel_id,
},
}).config({ name: "retrieve-restock-subscription" })
return new WorkflowResponse(
@@ -1116,12 +1120,12 @@ Before adding the step that does this, you'll add a method in the `RestockModule
```ts title="src/modules/restock/service.ts"
// other imports...
import { InjectManager, MedusaContext } from "@medusajs/framework/utils";
import { InjectManager, MedusaContext } from "@medusajs/framework/utils"
import { Context } from "@medusajs/framework/types"
import { EntityManager } from "@mikro-orm/knex";
import { EntityManager } from "@mikro-orm/knex"
class RestockModuleService extends MedusaService({
RestockSubscription
RestockSubscription,
}) {
// ...
@InjectManager()
@@ -1147,9 +1151,9 @@ You'll use this method in the step. To create the step, create the file `src/wor
![Directory structure of the Medusa application after adding the step.](https://res.cloudinary.com/dza7lstvk/image/upload/v1733399774/Medusa%20Resources/restock-dir-overview-22_kzchmm.jpg)
```ts title="src/workflows/send-restock-notifications/steps/get-distinct-subscriptions.ts"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk";
import RestockModuleService from "../../../modules/restock/service";
import { RESTOCK_MODULE } from "../../../modules/restock";
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import RestockModuleService from "../../../modules/restock/service"
import { RESTOCK_MODULE } from "../../../modules/restock"
export const getDistinctSubscriptionsStep = createStep(
"get-distinct-subscriptions",
@@ -1194,7 +1198,7 @@ export const getRestockedStep = createStep(
input.map(async (restockSubscription) => {
const variantAvailability = await getVariantAvailability(query, {
variant_ids: [restockSubscription.variant_id],
sales_channel_id: restockSubscription.sales_channel_id
sales_channel_id: restockSubscription.sales_channel_id,
})
if (variantAvailability[restockSubscription.variant_id].availability > 0) {
@@ -1318,12 +1322,12 @@ Create the file `src/workflows/send-restock-notifications/index.ts` with the fol
![The directory structure of the Medusa application after adding the workflow.](https://res.cloudinary.com/dza7lstvk/image/upload/v1733234507/Medusa%20Resources/restock-dir-overview-20_mcqkkx.jpg)
```ts title="src/workflows/send-restock-notifications/index.ts"
import { createWorkflow, transform, WorkflowResponse } from "@medusajs/framework/workflows-sdk";
import { useQueryGraphStep } from "@medusajs/medusa/core-flows";
import { getRestockedStep } from "./steps/get-restocked";
import { sendRestockNotificationStep } from "./steps/send-restock-notification";
import { deleteRestockSubscriptionStep } from "./steps/delete-restock-subscriptions";
import { getDistinctSubscriptionsStep } from "./steps/get-distinct-subscriptions";
import { createWorkflow, transform, WorkflowResponse } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
import { getRestockedStep } from "./steps/get-restocked"
import { sendRestockNotificationStep } from "./steps/send-restock-notification"
import { deleteRestockSubscriptionStep } from "./steps/delete-restock-subscriptions"
import { getDistinctSubscriptionsStep } from "./steps/get-distinct-subscriptions"
export const sendRestockNotificationsWorkflow = createWorkflow(
"send-restock-notifications",
@@ -1334,11 +1338,11 @@ export const sendRestockNotificationsWorkflow = createWorkflow(
const restockedSubscriptions = getRestockedStep(subscriptions)
const { variant_ids, sales_channel_ids } = transform({
restockedSubscriptions
restockedSubscriptions,
}, (data) => {
const filters: Record<string, string[]> = {
variant_ids: [],
sales_channel_ids: []
sales_channel_ids: [],
}
data.restockedSubscriptions.map((subscription) => {
filters.variant_ids.push(subscription.variant_id)
@@ -1354,8 +1358,8 @@ export const sendRestockNotificationsWorkflow = createWorkflow(
fields: ["*", "product_variant.*"],
filters: {
variant_id: variant_ids,
sales_channel_id: sales_channel_ids
}
sales_channel_id: sales_channel_ids,
},
})
// @ts-ignore
@@ -1365,7 +1369,7 @@ export const sendRestockNotificationsWorkflow = createWorkflow(
deleteRestockSubscriptionStep(restockedSubscriptionsWithEmails)
return new WorkflowResponse({
subscriptions: restockedSubscriptionsWithEmails
subscriptions: restockedSubscriptionsWithEmails,
})
}
)
@@ -1705,11 +1705,11 @@ export const createDpoWorkflowHighlights = [
["27", "completeCartWorkflow", "Create an order for the cart."],
["33", "useQueryGraphStep", "Retrieve the order's items and their associated variants and linked digital products."],
["57", "when", "Check whether the order has any digital products."],
["60", "then", "Perform the callback function if an order has digital products."],
["63", "createDigitalProductOrderStep", "Create the digital product order."],
["67", "createRemoteLinkStep", "Link the digital product order to the Medusa order."],
["76", "createOrderFulfillmentWorkflow", "Create a fulfillment for the digital products in the order."],
["90", "emitEventStep", "Emit the `digital_product_order.created` event."]
["63", "then", "Perform the callback function if an order has digital products."],
["66", "createDigitalProductOrderStep", "Create the digital product order."],
["70", "createRemoteLinkStep", "Link the digital product order to the Medusa order."],
["79", "createOrderFulfillmentWorkflow", "Create a fulfillment for the digital products in the order."],
["93", "emitEventStep", "Emit the `digital_product_order.created` event."]
]
```ts title="src/workflows/create-digital-product-order/index.ts" highlights={createDpoWorkflowHighlights} collapsibleLines="1-17" expandMoreLabel="Show Imports"
@@ -1769,10 +1769,13 @@ const createDigitalProductOrderWorkflow = createWorkflow(
}
)
const digital_product_order = when(itemsWithDigitalProducts, (itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length
})
.then(() => {
const digital_product_order = when(
"create-digital-product-order-condition",
itemsWithDigitalProducts,
(itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length
}
).then(() => {
const {
digital_product_order,
} = createDigitalProductOrderStep({
@@ -0,0 +1,24 @@
export const metadata = {
title: `Workflow Errors`,
}
# {metadata.title}
## When-Then Error: Handler for action X Not Found
The following error may occur in production if you use a `when-then` block in your workflow:
```plain
custom-workflow:when-then-01JE8Z0M1FXSE2NCK1G04S0RR2:invoke - Handler for action \"when-then-01JE8Z0M1FXSE2NCK1G04S0RR2\" not found...
```
This occurs if the `when-then` block doesn't return a step's result and doesn't have a name specified. You can resolve it by passing a name as a first parameter of `when`:
```ts
const result = when(
"custom-when-condition"
// ... rest of the parameters
)
```
Learn more about passing a name for `when-then` in [this documentation](!docs!/learn/fundamentals/workflows/conditions#specify-name-for-when-then)
+7 -6
View File
@@ -2180,15 +2180,15 @@ export const generatedEditDates = {
"app/commerce-modules/auth/reset-password/page.mdx": "2024-11-27T13:33:55.940Z",
"app/storefront-development/customers/reset-password/page.mdx": "2024-09-25T10:21:46.647Z",
"app/commerce-modules/api-key/links-to-other-modules/page.mdx": "2024-10-08T08:05:36.596Z",
"app/commerce-modules/cart/extend/page.mdx": "2024-12-09T16:11:39.857Z",
"app/commerce-modules/cart/extend/page.mdx": "2024-12-11T09:05:37.041Z",
"app/commerce-modules/cart/links-to-other-modules/page.mdx": "2024-10-08T08:22:35.190Z",
"app/commerce-modules/customer/extend/page.mdx": "2024-12-09T16:15:01.163Z",
"app/commerce-modules/customer/extend/page.mdx": "2024-12-11T09:05:35.368Z",
"app/commerce-modules/fulfillment/links-to-other-modules/page.mdx": "2024-10-08T14:58:24.935Z",
"app/commerce-modules/inventory/links-to-other-modules/page.mdx": "2024-10-08T15:18:30.109Z",
"app/commerce-modules/pricing/links-to-other-modules/page.mdx": "2024-10-09T13:51:49.986Z",
"app/commerce-modules/product/extend/page.mdx": "2024-12-09T16:15:01.163Z",
"app/commerce-modules/product/extend/page.mdx": "2024-12-11T09:07:25.252Z",
"app/commerce-modules/product/links-to-other-modules/page.mdx": "2024-10-09T14:14:09.401Z",
"app/commerce-modules/promotion/extend/page.mdx": "2024-12-09T16:19:19.364Z",
"app/commerce-modules/promotion/extend/page.mdx": "2024-12-11T09:07:24.137Z",
"app/commerce-modules/promotion/links-to-other-modules/page.mdx": "2024-10-09T14:51:37.194Z",
"app/commerce-modules/order/edit/page.mdx": "2024-10-09T08:50:05.334Z",
"app/commerce-modules/order/links-to-other-modules/page.mdx": "2024-10-09T11:23:05.488Z",
@@ -2246,7 +2246,7 @@ export const generatedEditDates = {
"app/commerce-modules/sales-channel/links-to-other-modules/page.mdx": "2024-10-15T14:25:29.097Z",
"app/commerce-modules/stock-location/links-to-other-modules/page.mdx": "2024-10-15T14:33:11.483Z",
"app/commerce-modules/store/links-to-other-modules/page.mdx": "2024-06-26T07:19:49.931Z",
"app/examples/page.mdx": "2024-12-09T16:19:18.598Z",
"app/examples/page.mdx": "2024-12-11T09:07:47.589Z",
"app/medusa-cli/commands/build/page.mdx": "2024-11-11T11:00:49.665Z",
"app/js-sdk/page.mdx": "2024-10-16T12:12:34.512Z",
"references/js_sdk/admin/Admin/properties/js_sdk.admin.Admin.apiKey/page.mdx": "2024-12-09T13:21:58.136Z",
@@ -5687,5 +5687,6 @@ export const generatedEditDates = {
"references/modules/sales_channel_models/page.mdx": "2024-12-10T14:55:13.205Z",
"references/types/DmlTypes/types/types.DmlTypes.KnownDataTypes/page.mdx": "2024-12-10T14:54:55.434Z",
"references/types/DmlTypes/types/types.DmlTypes.RelationshipTypes/page.mdx": "2024-12-10T14:54:55.435Z",
"app/recipes/commerce-automation/restock-notification/page.mdx": "2024-12-10T14:15:39.178Z"
"app/recipes/commerce-automation/restock-notification/page.mdx": "2024-12-11T08:47:27.471Z",
"app/troubleshooting/workflow-errors/page.mdx": "2024-12-11T08:44:36.598Z"
}
@@ -1019,6 +1019,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/troubleshooting/s3/page.mdx",
"pathname": "/troubleshooting/s3"
},
{
"filePath": "/www/apps/resources/app/troubleshooting/workflow-errors/page.mdx",
"pathname": "/troubleshooting/workflow-errors"
},
{
"filePath": "/www/apps/resources/app/usage/page.mdx",
"pathname": "/usage"
+8
View File
@@ -9309,6 +9309,14 @@ export const generatedSidebar = [
"path": "/troubleshooting/dist-imports",
"title": "Importing from /dist",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/troubleshooting/workflow-errors",
"title": "Workflow Errors",
"children": []
}
]
},
+5
View File
@@ -2249,6 +2249,11 @@ export const sidebar = sidebarAttachHrefCommonOptions([
path: "/troubleshooting/dist-imports",
title: "Importing from /dist",
},
{
type: "link",
path: "/troubleshooting/workflow-errors",
title: "Workflow Errors",
},
],
},
{