docs: general updates after 2.5.0 update (#11402)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-02-11 18:26:21 +02:00
1 parent ca486aa7ed
commit 5cb44d364d
17 files changed
+11580 -11569

No files matched your search

@@ -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 user’s authentication identity (created by the `/auth/{actor_type}/{provider}/register` API route). For this step, you’ll 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)
throw MedusaError.Types.INVALID_DATA
const driver = await deliveryModuleService.createDrivers(data)
return new StepResponse(driver, driver.id)
},
function ({ id, actor_type }, { container }) {
// TODO add compensation actions
async (id, { container }) => {
if (!id) {
return
}
)
```
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.
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 Module’s 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 Module’s 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)
}
await service.deleteRestaurantAdmins(id)
}
)
```
In the compensation function, if the `actor_type` is a restaurant, you delete the created restaurant admin. Otherwise, you delete the created driver.
This creates a step that accepts as input the data of the driver to create. The step creates a driver and returns it.
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) => ({
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: data.user.id,
}))
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",