docs: general updates after 2.5.0 update (#11402)

This commit is contained in:
Shahed Nasser
2025-02-11 18:26:21 +02:00
committed by GitHub
parent ca486aa7ed
commit 5cb44d364d
17 changed files with 11576 additions and 11565 deletions
@@ -288,7 +288,7 @@ const columns = [
}),
columnHelper.accessor("name", {
header: "Name",
})
}),
]
```
@@ -337,10 +337,10 @@ medusaIntegrationTestRunner({
{
type: "publishable",
title: "Test Key",
created_by: ""
}
]
}
created_by: "",
},
],
},
})).result[0]
})
describe("GET /custom", () => {
@@ -349,8 +349,8 @@ medusaIntegrationTestRunner({
`/store/custom`,
{
headers: {
"x-publishable-api-key": pak.token
}
"x-publishable-api-key": pak.token,
},
}
)
@@ -421,13 +421,13 @@ medusaIntegrationTestRunner({
provider: "emailpass",
entity_id: "admin@medusa.js",
provider_metadata: {
password: "supersecret"
}
}
password: "supersecret",
},
},
],
app_metadata: {
user_id: user.id
}
user_id: user.id,
},
})
const token = jwt.sign(
@@ -503,13 +503,13 @@ medusaIntegrationTestRunner({
provider: "emailpass",
entity_id: "customer@medusa.js",
provider_metadata: {
password: "supersecret"
}
}
password: "supersecret",
},
},
],
app_metadata: {
user_id: customer.id
}
user_id: customer.id,
},
})
const token = jwt.sign(
@@ -533,10 +533,10 @@ medusaIntegrationTestRunner({
{
type: "publishable",
title: "Test Key",
created_by: ""
}
]
}
created_by: "",
},
],
},
})).result[0]
headers["x-publishable-api-key"] = pak.token
@@ -126,7 +126,7 @@ medusaIntegrationTestRunner({
it("returns message", async () => {
const { errors } = await helloWorldWorkflow(getContainer())
.run({
throwOnError: false
throwOnError: false,
})
expect(errors.length).toBeGreaterThan(0)
@@ -10,59 +10,59 @@ In this chapter, you'll learn how to manage relationships between data models wh
### BelongsTo Side of One-to-One
When you create a record of a data model that belongs to another through a one-to-one relation, pass the ID of the other data model's record in the relation property.
When you create a record of a data model that belongs to another through a one-to-one relation, pass the ID of the other data model's record in the `{relation}_id` property, where `{relation}` is the name of the relation property.
For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship), set an email's user ID as follows:
export const belongsHighlights = [
["4", "user", "The ID of the user the email belongs to."],
["11", "user", "The ID of the user the email belongs to."]
["4", "user_id", "The ID of the user the email belongs to."],
["11", "user_id", "The ID of the user the email belongs to."]
]
```ts highlights={belongsHighlights}
// when creating an email
const email = await helloModuleService.createEmails({
// other properties...
user: "123",
user_id: "123",
})
// when updating an email
const email = await helloModuleService.updateEmails({
id: "321",
// other properties...
user: "123",
user_id: "123",
})
```
In the example above, you pass the `user` property when creating or updating an email to specify the user it belongs to.
In the example above, you pass the `user_id` property when creating or updating an email to specify the user it belongs to.
### HasOne Side
When you create a record of a data model that has one of another, pass the ID of the other data model's record in the relation property.
When you create a record of a data model that has one of another, pass the ID of the other data model's record in the `{relation}_id` property, where `{relation}` is the name of the relation property.
For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship), set a user's email ID as follows:
export const hasOneHighlights = [
["4", "email", "The ID of the email that the user has."],
["11", "email", "The ID of the email that the user has."]
["4", "email_id", "The ID of the email that the user has."],
["11", "email_id", "The ID of the email that the user has."]
]
```ts highlights={hasOneHighlights}
// when creating a user
const user = await helloModuleService.createUsers({
// other properties...
email: "123",
email_id: "123",
})
// when updating a user
const user = await helloModuleService.updateUsers({
id: "321",
// other properties...
email: "123",
email_id: "123",
})
```
In the example above, you pass the `email` property when creating or updating a user to specify the email it has.
In the example above, you pass the `email_id` property when creating or updating a user to specify the email it has.
---
@@ -33,7 +33,7 @@ const { data } = await query.graph({
fields: ["*"],
context: QueryContext({
lang: "es",
})
}),
})
```
@@ -58,7 +58,7 @@ import Author from "./models/author"
class BlogModuleService extends MedusaService({
Post,
Author
Author,
}){
// @ts-ignore
async listPosts(
@@ -125,8 +125,8 @@ const { data } = await query.graph({
lang: "es",
author: QueryContext({
lang: "es",
})
})
}),
}),
})
```
@@ -144,7 +144,7 @@ import Author from "./models/author"
class BlogModuleService extends MedusaService({
Post,
Author
Author,
}){
// @ts-ignore
async listPosts(
@@ -168,7 +168,7 @@ class BlogModuleService extends MedusaService({
author: {
...post.author,
name: isAuthorLangEs ? post.author.name + " en español" : post.author.name,
}
},
}
})
}
@@ -201,8 +201,8 @@ const { data } = await query.graph({
context: {
post: QueryContext({
lang: "es",
})
}
}),
},
})
```
@@ -50,7 +50,7 @@ import { createStep, createWorkflow } from "@medusajs/framework/workflows-sdk"
const step1 = createStep(
{
name: "step-1"
name: "step-1",
},
async () => {
console.log("Hello from step 1")
@@ -61,7 +61,7 @@ export const helloWorkflow = createWorkflow(
{
name: "hello-workflow",
retentionTime: 99999,
store: true
store: true,
},
() => {
step1()
@@ -98,8 +98,8 @@ export const retrieveHighlights = [
]
```ts title="src/workflows/[id]/route.ts" highlights={retrieveHighlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/framework";
import { Modules } from "@medusajs/framework/utils";
import { MedusaRequest, MedusaResponse } from "@medusajs/framework"
import { Modules } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
@@ -112,11 +112,11 @@ export async function GET(
)
const [workflowExecution] = await workflowEngineService.listWorkflowExecutions({
transaction_id: transaction_id
transaction_id: transaction_id,
})
res.json({
workflowExecution
workflowExecution,
})
}
```
@@ -165,7 +165,7 @@ To check if a stored workflow execution failed, you can check its `state` proper
```ts
if (workflowExecution.state === "failed") {
return res.status(500).json({
error: "Workflow failed"
error: "Workflow failed",
})
}
```
+6 -6
View File
@@ -38,7 +38,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2025-01-27T08:45:19.028Z",
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2024-12-12T15:09:41.179Z",
"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-12-12T14:23:26.254Z",
"app/learn/fundamentals/data-models/manage-relationships/page.mdx": "2025-02-11T15:53:12.541Z",
"app/learn/fundamentals/modules/remote-query/page.mdx": "2024-07-21T21:20:24+02:00",
"app/learn/fundamentals/modules/options/page.mdx": "2025-01-16T09:21:38.244Z",
"app/learn/fundamentals/data-models/relationships/page.mdx": "2025-02-03T08:01:18.094Z",
@@ -59,9 +59,9 @@ export const generatedEditDates = {
"app/learn/fundamentals/data-models/index/page.mdx": "2024-10-21T13:30:21.368Z",
"app/learn/fundamentals/custom-cli-scripts/page.mdx": "2024-10-23T07:08:55.898Z",
"app/learn/fundamentals/data-models/property-types/page.mdx": "2024-12-12T10:41:32.999Z",
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-02-07T12:16:51.237Z",
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-02-11T15:56:03.835Z",
"app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-12-09T15:52:01.019Z",
"app/learn/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2025-01-31T13:19:02.586Z",
"app/learn/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2025-02-11T15:56:03.835Z",
"app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-01-31T13:19:02.587Z",
"app/learn/debugging-and-testing/testing-tools/unit-tests/module-example/page.mdx": "2024-09-02T11:04:27.232Z",
"app/learn/debugging-and-testing/testing-tools/unit-tests/page.mdx": "2024-09-02T11:03:26.997Z",
@@ -88,7 +88,7 @@ export const generatedEditDates = {
"app/learn/customization/extend-features/extend-create-product/page.mdx": "2025-01-06T11:18:58.250Z",
"app/learn/customization/custom-features/page.mdx": "2024-12-09T10:46:28.593Z",
"app/learn/customization/customize-admin/page.mdx": "2024-12-09T11:02:38.801Z",
"app/learn/customization/customize-admin/route/page.mdx": "2025-02-05T09:09:11.472Z",
"app/learn/customization/customize-admin/route/page.mdx": "2025-02-11T15:56:03.835Z",
"app/learn/customization/customize-admin/widget/page.mdx": "2025-02-05T09:10:18.163Z",
"app/learn/customization/extend-features/define-link/page.mdx": "2024-12-09T11:02:39.346Z",
"app/learn/customization/extend-features/page.mdx": "2024-12-09T11:02:39.244Z",
@@ -110,11 +110,11 @@ export const generatedEditDates = {
"app/learn/fundamentals/data-models/check-constraints/page.mdx": "2024-12-06T14:34:50.384Z",
"app/learn/fundamentals/module-links/link/page.mdx": "2025-01-06T09:27:25.604Z",
"app/learn/conventions/ts-aliases/page.mdx": "2025-01-23T15:01:15.403Z",
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-01-27T08:45:19.028Z",
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-02-11T15:56:03.835Z",
"app/learn/fundamentals/plugins/create/page.mdx": "2025-02-07T10:26:53.059Z",
"app/learn/fundamentals/plugins/page.mdx": "2025-01-22T10:14:10.433Z",
"app/learn/customization/reuse-customizations/page.mdx": "2025-01-22T10:01:57.665Z",
"app/learn/update/page.mdx": "2025-01-27T08:45:19.030Z",
"app/learn/fundamentals/module-links/query-context/page.mdx": "2025-02-03T17:04:24.479Z",
"app/learn/fundamentals/module-links/query-context/page.mdx": "2025-02-11T15:56:03.835Z",
"app/learn/fundamentals/admin/environment-variables/page.mdx": "2025-02-06T13:29:46.800Z"
}
File diff suppressed because it is too large Load Diff
@@ -227,11 +227,11 @@ export default class MetalPricesModuleService {
return fetch(`https://www.goldapi.io/api/${upperCaseSymbol}/${upperCaseCurrency}`, {
headers: {
'x-access-token': this.options_.accessToken,
"Content-Type": "application/json"
"x-access-token": this.options_.accessToken,
"Content-Type": "application/json",
},
redirect: "follow"
}).then(response => response.json())
redirect: "follow",
}).then((response) => response.json())
.then((response) => {
if (response.error) {
throw new MedusaError(
@@ -286,13 +286,13 @@ So, create the file `src/modules/metal-prices/index.ts` with the following conte
![The directory structure of the Metal Prices Module after adding the definition file.](https://res.cloudinary.com/dza7lstvk/image/upload/v1738248049/Medusa%20Resources/custom-item-price-3_imtbuw.jpg)
```ts title="src/modules/metal-prices/index.ts"
import { Module } from "@medusajs/framework/utils";
import MetalPricesModuleService from "./service";
import { Module } from "@medusajs/framework/utils"
import MetalPricesModuleService from "./service"
export const METAL_PRICES_MODULE = "metal-prices"
export default Module(METAL_PRICES_MODULE, {
service: MetalPricesModuleService
service: MetalPricesModuleService,
})
```
@@ -315,8 +315,8 @@ module.exports = defineConfig({
resolve: "./src/modules/metal-prices",
options: {
accessToken: process.env.GOLD_API_TOKEN,
sandbox: process.env.GOLD_API_SANDBOX === "true"
}
sandbox: process.env.GOLD_API_SANDBOX === "true",
},
},
],
})
@@ -409,10 +409,10 @@ To create the step, create the file `src/workflows/steps/get-variant-metal-price
![The directory structure after adding the step file.](https://res.cloudinary.com/dza7lstvk/image/upload/v1738249036/Medusa%20Resources/custom-item-price-4_kumzdc.jpg)
```ts title="src/workflows/steps/get-variant-metal-prices.ts"
import { createStep } from "@medusajs/framework/workflows-sdk";
import { createStep } from "@medusajs/framework/workflows-sdk"
import { ProductVariantDTO } from "@medusajs/framework/types"
import { METAL_PRICES_MODULE } from "../../modules/metal-prices";
import MetalPricesModuleService from "../../modules/metal-prices/service";
import { METAL_PRICES_MODULE } from "../../modules/metal-prices"
import MetalPricesModuleService from "../../modules/metal-prices/service"
export type GetVariantMetalPricesStepInput = {
variant: ProductVariantDTO & {
@@ -429,7 +429,7 @@ export const getVariantMetalPricesStep = createStep(
async ({
variant,
currencyCode,
quantity = 1
quantity = 1,
}: GetVariantMetalPricesStepInput, { container }) => {
const metalPricesModuleService: MetalPricesModuleService =
container.resolve(METAL_PRICES_MODULE)
@@ -546,19 +546,19 @@ export const addCustomToCartWorkflow = createWorkflow(
"*",
"options.*",
"options.option.*",
"calculated_price.*"
"calculated_price.*",
],
filters: {
id: item.variant_id
id: item.variant_id,
},
options: {
throwIfKeyNotFound: true
throwIfKeyNotFound: true,
},
context: {
calculated_price: QueryContext({
currency_code: carts[0].currency_code
})
}
currency_code: carts[0].currency_code,
}),
},
}).config({ name: "retrieve-variant" })
// TODO add more steps
@@ -580,7 +580,7 @@ Next, you'll retrieve the variant's real-time price using the `getVariantMetalPr
```ts title="src/workflows/add-custom-to-cart.ts"
import {
getVariantMetalPricesStep,
GetVariantMetalPricesStepInput
GetVariantMetalPricesStepInput,
} from "./steps/get-variant-metal-prices"
```
@@ -590,7 +590,7 @@ Then, replace the `TODO` in the workflow with the following:
const price = getVariantMetalPricesStep({
variant: variants[0],
currencyCode: carts[0].currency_code,
quantity: item.quantity
quantity: item.quantity,
} as unknown as GetVariantMetalPricesStepInput)
// TODO add item with custom price to cart
@@ -610,19 +610,19 @@ Then, replace the `TODO` in the workflow with the following:
```ts title="src/workflows/add-custom-to-cart.ts"
const itemToAdd = transform({
item,
price
price,
}, (data) => {
return [{
...data.item,
unit_price: data.price
unit_price: data.price,
}]
})
addToCartWorkflow.runAsStep({
input: {
items: itemToAdd,
cart_id
}
cart_id,
},
})
// TODO retrieve and return cart
@@ -653,7 +653,7 @@ const { data: updatedCarts } = useQueryGraphStep({
}).config({ name: "refetch-cart" })
return new WorkflowResponse({
cart: updatedCarts[0]
cart: updatedCarts[0],
})
```
@@ -699,8 +699,8 @@ export const POST = async (
.run({
input: {
cart_id: id,
item
}
item,
},
})
res.status(200).json({ cart: result.cart })
@@ -740,7 +740,7 @@ import {
validateAndTransformBody,
} from "@medusajs/framework/http"
import {
StoreAddCartLineItem
StoreAddCartLineItem,
} from "@medusajs/medusa/api/store/carts/validators"
export default defineMiddlewares({
@@ -750,10 +750,10 @@ export default defineMiddlewares({
method: "POST",
middlewares: [
validateAndTransformBody(
StoreAddCartLineItem,
)
]
}
StoreAddCartLineItem
),
],
},
],
})
```
@@ -624,6 +624,9 @@ export const createWishlistStep = createStep(
return new StepResponse(wishlist, wishlist.id)
},
async (id, { container }) => {
if (!id) {
return
}
const wishlistModuleService: WishlistModuleService =
container.resolve(WISHLIST_MODULE)
@@ -1108,6 +1111,9 @@ export const createWishlistItemStep = createStep(
return new StepResponse(item, item.id)
},
async (id, { container }) => {
if (!id) {
return
}
const wishlistModuleService: WishlistModuleService =
container.resolve(WISHLIST_MODULE)
@@ -524,6 +524,9 @@ Since the `createRestockSubscriptionStep` creates a restock subscription, you'll
export const createOrGetRestockSubscriptionsStep = createStep(
// ...
async (restockSubscription, { container }) => {
if (!restockSubscription) {
return
}
const restockModuleService: RestockModuleService = container.resolve(
RESTOCK_MODULE
)
@@ -576,6 +579,9 @@ export const updateRestockSubscriptionStep = createStep(
return new StepResponse(restockSubscription, oldData)
},
async (restockSubscription, { container }) => {
if (!restockSubscription) {
return
}
const restockModuleService: RestockModuleService = container.resolve(
RESTOCK_MODULE
)
@@ -745,20 +745,16 @@ To implement and expose a feature that manipulates data, you create a workflow t
So, you'll start by implementing the functionality to create a user in a workflow. The workflow has two steps:
1. Create the user in the database.
1. Create the user in the database. This user is either a restaurant admin or a driver. So, you'll create two separate steps for each user type.
2. Set the actor type of the users authentication identity (created by the `/auth/{actor_type}/{provider}/register` API route). For this step, youll use `setAuthAppMetadataStep` from Medusa's core workflows.
To implement the first step, create the file `src/workflows/user/steps/create-user.ts` with the following content:
You'll start by implementing the steps to create a restaurant admin. Create the file `
```ts title="src/workflows/user/steps/create-user.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports"
import { MedusaError } from "@medusajs/framework/utils"
To implement the first step, create the file `src/workflows/user/steps/create-restaurant-admin.ts` with the following content:
```ts title="src/workflows/user/steps/create-restaurant-admin.ts"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import {
CreateDriverInput,
CreateRestaurantAdminInput,
} from "../workflows/create-user"
import { RESTAURANT_MODULE } from "../../../modules/restaurant"
import { DELIVERY_MODULE } from "../../../modules/delivery"
export type CreateRestaurantAdminInput = {
restaurant_id: string;
@@ -767,6 +763,43 @@ export type CreateRestaurantAdminInput = {
last_name: string;
};
export const createRestaurantAdminStep = createStep(
"create-restaurant-admin-step",
async (
data: CreateRestaurantAdminInput,
{ container }
) => {
const restaurantModuleService = container.resolve(RESTAURANT_MODULE)
const restaurantAdmin = await restaurantModuleService.createRestaurantAdmins(
data
)
return new StepResponse(restaurantAdmin, restaurantAdmin.id)
},
async (id, { container }) => {
if (!id) {
return
}
const service = container.resolve(RESTAURANT_MODULE)
await service.deleteRestaurantAdmins(id)
}
)
```
This creates a step that accepts as input the data of the restaurant to create and its type. The step creates a restaurant admin and returns it.
In the compensation function, you delete the created restaurant admin if an error occurs.
Then, to implement the step that creates a driver, create the file `src/workflows/user/steps/create-driver.ts` with the following content:
```ts title="src/workflows/user/steps/create-driver.ts"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
import { RESTAURANT_MODULE } from "../../../modules/restaurant"
import { DELIVERY_MODULE } from "../../../modules/delivery"
export type CreateDriverInput = {
email: string;
first_name: string;
@@ -775,101 +808,49 @@ export type CreateDriverInput = {
avatar_url?: string;
};
type CreateUserStepInput = (CreateRestaurantAdminInput | CreateDriverInput) & {
actor_type: "restaurant" | "driver";
};
export const createUserStep = createStep(
"create-user-step",
export const createDriverStep = createStep(
"create-driver-step",
async (
{ actor_type, ...data }: CreateUserStepInput,
data: CreateDriverInput,
{ container }
) => {
if (actor_type === "restaurant") {
// TODO create restaurant admin
} else if (actor_type === "driver") {
// TODO create driver
const deliveryModuleService = container.resolve(DELIVERY_MODULE)
const driver = await deliveryModuleService.createDrivers(data)
return new StepResponse(driver, driver.id)
},
async (id, { container }) => {
if (!id) {
return
}
throw MedusaError.Types.INVALID_DATA
},
function ({ id, actor_type }, { container }) {
// TODO add compensation actions
const service = container.resolve(RESTAURANT_MODULE)
await service.deleteRestaurantAdmins(id)
}
)
```
This creates a step that accepts as input the data of the user to create and its type. If the type is `restaurant`, then a restaurant admin is created. If the type is a `driver`, then a driver is created. Otherwise, an error is thrown.
This creates a step that accepts as input the data of the driver to create. The step creates a driver and returns it.
Replace the first `TODO` with the following to create a restaurant admin:
```ts title="src/workflows/user/steps/create-user.ts"
const service = container.resolve(RESTAURANT_MODULE)
const restaurantAdmin = await service.createRestaurantAdmins(
data
)
return new StepResponse(restaurantAdmin, {
id: restaurantAdmin.id,
actor_type: actor_type as string,
})
```
This resolves the Restaurant Modules main service, creates the restaurant admin, and returns it.
Then, replace the second `TODO` with the following to create a driver:
```ts title="src/workflows/user/steps/create-user.ts"
const service = container.resolve(DELIVERY_MODULE)
const driver = await service.createDrivers(data)
return new StepResponse(driver, {
id: driver.id,
actor_type: actor_type as string,
})
```
This resolves the Driver Modules main service, creates the driver, and returns it.
Finally, replace the remaining `TODO` with the following compensation action:
```ts title="src/workflows/user/steps/create-user.ts"
if (actor_type === "restaurant") {
const service = container.resolve(RESTAURANT_MODULE)
return service.deleteRestaurantAdmins(id)
} else {
const service = container.resolve(DELIVERY_MODULE)
return service.deleteDrivers(id)
}
```
In the compensation function, if the `actor_type` is a restaurant, you delete the created restaurant admin. Otherwise, you delete the created driver.
In the compensation function, you delete the created driver if an error occurs.
Next, create the workflow in the file `src/workflows/user/workflows/create-user.ts`:
```ts title="src/workflows/user/workflows/create-user.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports"
```ts title="src/workflows/user/workflows/create-user.ts" collapsibleLines="1-13" expandButtonLabel="Show Imports"
import { setAuthAppMetadataStep } from "@medusajs/medusa/core-flows"
import {
createWorkflow,
transform,
when,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { CreateDriverInput, createDriverStep } from "../steps/create-driver"
import {
CreateDriverInput,
CreateRestaurantAdminInput,
createUserStep,
} from "../steps/create-user"
type WorkflowInput = {
user: (CreateRestaurantAdminInput | CreateDriverInput) & {
actor_type: "restaurant" | "driver";
};
auth_identity_id: string;
};
createRestaurantAdminStep,
} from "../steps/create-restaurant-admin"
export type CreateUserWorkflowInput = {
user: (CreateRestaurantAdminInput | CreateDriverInput) & {
@@ -884,7 +865,6 @@ export const createUserWorkflow = createWorkflow(
// TODO create user
}
)
```
In this file, you create the necessary types and the workflow with a `TODO`.
@@ -892,20 +872,38 @@ In this file, you create the necessary types and the workflow with a `TODO`.
Replace the `TODO` with the following:
export const createUserHighlights = [
["1", "createUserStep", "Create the user."],
["3", "transform", "Define the input for the next step."],
["6", "key", "Set the key based on whether the user is a restaurant admin or a driver."],
["13", "setAuthAppMetadataStep", "Update the authentication identity with to associate it with the new user."]
["1", "restaurantUser", "Create a restaurant user if the actor type is `restaurant`."],
["8", "driverUser", "Create a driver if the actor type is `driver`."],
["15", "transform", "Define the input for the next step."],
["27", "setAuthAppMetadataStep", "Update the authentication identity to associate it with the new user."]
]
```ts title="src/workflows/user/workflows/create-user.ts" highlights={createUserHighlights}
const user = createUserStep(input.user)
const restaurantUser = when(input, (input) => input.user.actor_type === "restaurant")
.then(() => {
return createRestaurantAdminStep(
input.user as CreateRestaurantAdminInput
)
})
const authUserInput = transform({ input, user }, (data) => ({
authIdentityId: data.input.auth_identity_id,
actorType: data.input.user.actor_type,
value: data.user.id,
}))
const driverUser = when(input, (input) => input.user.actor_type === "driver")
.then(() => {
return createDriverStep(
input.user as CreateDriverInput
)
})
const { user, authUserInput } = transform({ input, restaurantUser, driverUser }, (data) => {
const user = data.restaurantUser || data.driverUser
return {
user,
authUserInput: {
authIdentityId: data.input.auth_identity_id,
actorType: data.input.user.actor_type,
value: user.id,
},
}
})
setAuthAppMetadataStep(authUserInput)
@@ -914,10 +912,11 @@ return new WorkflowResponse(user)
In the workflow, you:
1. Use the `createUserStep` to create the user.
2. Use `transform` to create the input to be passed to the next step.
3. Use `setAuthAppMetadataStep` from Medusa's core workflows to update the authentication identity and associate it with the new user.
4. Return the created user.
1. Create a restaurant admin if the actor type is `restaurant`.
2. Create a driver if the actor type is `driver`.
3. Use `transform` to create the input to be passed to the next step and return the created user, which is either a restaurant admin or a driver.
4. Use `setAuthAppMetadataStep` from Medusa's core workflows to update the authentication identity and associate it with the new user.
5. Return the created user.
### Create API Route
@@ -1294,7 +1293,7 @@ import {
createProductsWorkflow,
createRemoteLinkStep,
} from "@medusajs/medusa/core-flows"
import { CreateProductDTO } from "@medusajs/framework/types"
import { CreateProductWorkflowInputDTO } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
import {
WorkflowResponse,
@@ -1304,7 +1303,7 @@ import {
import { RESTAURANT_MODULE } from "../../../modules/restaurant"
type WorkflowInput = {
products: CreateProductDTO[];
products: CreateProductWorkflowInputDTO[];
restaurant_id: string;
};
@@ -468,7 +468,7 @@ export const POST = async (
.resolve("marketplaceModuleService")
// create vendor
let vendor = await marketplaceModuleService.createVendors([vendorData])
let vendor = await marketplaceModuleService.createVendors(vendorData)
// create vendor admin
await createVendorAdminWorkflow(req.scope)
@@ -1705,7 +1705,7 @@ class SubscriptionModuleService extends MedusaService({
Subscription,
}) {
// ...
async recordNewSubscriptionOrder(id: string): Promise<SubscriptionData[]> {
async recordNewSubscriptionOrder(id: string) {
const subscription = await this.retrieveSubscription(id)
const orderDate = new Date()
@@ -272,7 +272,7 @@ const updateCartAddress = (customerAddress: Record<string, unknown>) => {
city: customerAddress.city || "",
country_code: customerAddress.country_code || cart.region?.countries?.[0].iso_2,
province: customerAddress.province || "",
phone: customerAddress.phone || ""
phone: customerAddress.phone || "",
}
fetch(`http://localhost:9000/store/carts/${cart.id}`, {
@@ -284,8 +284,8 @@ const updateCartAddress = (customerAddress: Record<string, unknown>) => {
},
body: JSON.stringify({
shipping_address: address,
billing_address: address
})
billing_address: address,
}),
})
.then((res) => res.json())
.then(({ cart: updatedCart }) => {
@@ -312,11 +312,11 @@ export const react2Highlights = [
```tsx highlights={react2Highlights}
"use client" // include with Next.js 13+
import { useEffect, useState } from "react";
import { useCart } from "../../../providers/cart";
import { useCustomer } from "../../../providers/customer";
import { useEffect, useState } from "react"
import { useCart } from "../../../providers/cart"
import { useCustomer } from "../../../providers/customer"
export default function CheckoutAddressStep () {
export default function CheckoutAddressStep() {
const { cart, setCart } = useCart()
const { customer } = useCustomer()
const [loading, setLoading] = useState(false)
@@ -349,7 +349,7 @@ export default function CheckoutAddressStep () {
city: customerAddress.city || "",
country_code: customerAddress.country_code || cart.region?.countries?.[0].iso_2,
province: customerAddress.province || "",
phone: customerAddress.phone || ""
phone: customerAddress.phone || "",
}
fetch(`http://localhost:9000/store/carts/${cart.id}`, {
@@ -361,8 +361,8 @@ export default function CheckoutAddressStep () {
},
body: JSON.stringify({
shipping_address: address,
billing_address: address
})
billing_address: address,
}),
})
.then((res) => res.json())
.then(({ cart: updatedCart }) => {
@@ -69,7 +69,7 @@ module.exports = defineConfig({
optimizeDeps: {
include: ["qs"],
},
};
}
},
},
// ...
+5 -5
View File
@@ -116,14 +116,14 @@ export const generatedEditDates = {
"app/recipes/digital-products/page.mdx": "2025-01-06T11:19:35.623Z",
"app/recipes/ecommerce/page.mdx": "2024-10-22T11:01:01.218Z",
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-12-09T13:03:35.846Z",
"app/recipes/marketplace/examples/vendors/page.mdx": "2025-01-06T11:19:35.639Z",
"app/recipes/marketplace/examples/vendors/page.mdx": "2025-02-11T12:59:00.539Z",
"app/recipes/marketplace/page.mdx": "2024-10-03T13:07:44.153Z",
"app/recipes/multi-region-store/page.mdx": "2024-10-03T13:07:13.813Z",
"app/recipes/omnichannel/page.mdx": "2024-10-03T13:07:14.384Z",
"app/recipes/oms/page.mdx": "2024-07-01T10:21:19+03:00",
"app/recipes/personalized-products/page.mdx": "2024-10-03T13:07:44.153Z",
"app/recipes/pos/page.mdx": "2024-10-03T13:07:13.964Z",
"app/recipes/subscriptions/examples/standard/page.mdx": "2025-02-04T07:37:14.832Z",
"app/recipes/subscriptions/examples/standard/page.mdx": "2025-02-11T14:21:09.533Z",
"app/recipes/subscriptions/page.mdx": "2024-10-03T13:07:44.155Z",
"app/recipes/page.mdx": "2024-07-11T15:56:41+00:00",
"app/service-factory-reference/methods/create/page.mdx": "2024-07-31T17:01:33+03:00",
@@ -577,7 +577,7 @@ export const generatedEditDates = {
"app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z",
"app/medusa-cli/commands/telemtry/page.mdx": "2025-01-16T09:51:24.323Z",
"app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z",
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-12-11T10:05:52.851Z",
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2025-02-11T15:51:17.490Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-12-09T13:21:33.569Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-12-09T13:21:34.505Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-12-23T13:57:05.262Z",
@@ -5583,7 +5583,7 @@ 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-17T16:57:19.922Z",
"references/types/DmlTypes/types/types.DmlTypes.RelationshipTypes/page.mdx": "2024-12-10T14:54:55.435Z",
"app/recipes/commerce-automation/restock-notification/page.mdx": "2025-01-23T10:18:28.126Z",
"app/recipes/commerce-automation/restock-notification/page.mdx": "2025-02-11T13:29:56.235Z",
"app/troubleshooting/workflow-errors/page.mdx": "2024-12-11T08:44:36.598Z",
"app/integrations/guides/shipstation/page.mdx": "2025-01-07T14:40:42.561Z",
"app/nextjs-starter/guides/customize-stripe/page.mdx": "2024-12-25T14:48:55.877Z",
@@ -5860,7 +5860,7 @@ export const generatedEditDates = {
"references/core_flows/types/core_flows.ThrowUnlessPaymentCollectionNotePaidInput/page.mdx": "2025-01-17T16:43:25.819Z",
"references/core_flows/types/core_flows.ValidatePaymentsRefundStepInput/page.mdx": "2025-01-17T16:43:26.128Z",
"references/core_flows/types/core_flows.ValidateRefundStepInput/page.mdx": "2025-01-17T16:43:26.124Z",
"app/plugins/guides/wishlist/page.mdx": "2025-02-05T09:12:22.965Z",
"app/plugins/guides/wishlist/page.mdx": "2025-02-11T14:25:46.734Z",
"app/plugins/page.mdx": "2025-01-22T09:36:37.745Z",
"app/admin-components/components/data-table/page.mdx": "2025-01-22T16:01:01.279Z",
"references/order_models/variables/order_models.Order/page.mdx": "2025-01-27T11:43:58.788Z",