docs: added troubleshooting guides + improvements (#11927)
* docs: added troubleshooting guides + improvements * build fixes
This commit is contained in:
1 parent
c4f75ecbb2
commit
4c33586946
35 files changed
+17253
-15859
No files matched your search
@@ -11,6 +11,8 @@ You can customize the admin dashboard by:
|
|||||||
- Adding new sections to existing pages using Widgets.
|
- Adding new sections to existing pages using Widgets.
|
||||||
- Adding new pages using UI Routes.
|
- Adding new pages using UI Routes.
|
||||||
|
|
||||||
|
However, you can't customize the admin dashboard's layout, design, or the content of the existing pages (aside from injecting widgets).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Medusa UI Package
|
## Medusa UI Package
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ export const GET = async (
|
|||||||
) => {
|
) => {
|
||||||
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "title"],
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ my_customs: myCustoms })
|
res.json({ posts })
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ The method returns an object that has a `data` property, which holds an array of
|
|||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
"id": "123",
|
"id": "123",
|
||||||
"name": "test"
|
"title": "My Post"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -88,21 +88,33 @@ Retrieve the records of a linked data model by passing in `fields` the data mode
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```ts highlights={[["6"]]}
|
```ts highlights={[["6"]]}
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: [
|
fields: [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"title",
|
||||||
"product.*",
|
"product.*",
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
<Note title="Tip">
|
`.*` means that all of data model's properties should be retrieved. You can also retrieve specific properties by replacing the `*` with the property name, for each property.
|
||||||
|
|
||||||
`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`.
|
For example:
|
||||||
|
|
||||||
</Note>
|
```ts
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"product.id",
|
||||||
|
"product.title",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, you retrieve only the `id` and `title` properties of the `product` linked to a `post`.
|
||||||
|
|
||||||
### Retrieve List Link Records
|
### Retrieve List Link Records
|
||||||
|
|
||||||
@@ -111,19 +123,21 @@ If the linked data model has `isList` enabled in the link definition, pass in `f
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```ts highlights={[["6"]]}
|
```ts highlights={[["6"]]}
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: [
|
fields: [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"title",
|
||||||
"products.*",
|
"products.*",
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In the example above, you retrieve all products linked to a post.
|
||||||
|
|
||||||
### Apply Filters and Pagination on Linked Records
|
### Apply Filters and Pagination on Linked Records
|
||||||
|
|
||||||
Consider you want to apply filters or pagination configurations on the product(s) linked to `my_custom`. To do that, you must query the module link's table instead.
|
Consider you want to apply filters or pagination configurations on the product(s) linked to `post`. To do that, you must query the module link's table instead.
|
||||||
|
|
||||||
As mentioned in the [Module Link](../page.mdx) documentation, Medusa creates a table for your module link. So, not only can you retrieve linked records, but you can also retrieve the records in a module link's table.
|
As mentioned in the [Module Link](../page.mdx) documentation, Medusa creates a table for your module link. So, not only can you retrieve linked records, but you can also retrieve the records in a module link's table.
|
||||||
|
|
||||||
@@ -133,19 +147,19 @@ For example:
|
|||||||
|
|
||||||
export const queryLinkTableHighlights = [
|
export const queryLinkTableHighlights = [
|
||||||
["1", "", "Import the module link."],
|
["1", "", "Import the module link."],
|
||||||
["6", "productBrandLink.entryPoint", "Pass the `entryPoint` property of the link to Query"],
|
["6", "ProductPostLink.entryPoint", "Pass the `entryPoint` property of the link to Query"],
|
||||||
["7", `"product.*"`, "Retrieve the fields of a product record linked to a `MyCustom` record."],
|
["7", `"product.*"`, "Retrieve the fields of a product record linked to a `Post` record."],
|
||||||
["7", `"brand.*"`, "Retrieve the fields of a `MyCustom` record linked to a product record."]
|
["7", `"post.*"`, "Retrieve the fields of a `Post` record linked to a product record."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts highlights={queryLinkTableHighlights}
|
```ts highlights={queryLinkTableHighlights}
|
||||||
import productCustomLink from "../../../links/product-custom"
|
import ProductPostLink from "../../../links/product-post"
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
const { data: productCustoms } = await query.graph({
|
const { data: productCustoms } = await query.graph({
|
||||||
entity: productCustomLink.entryPoint,
|
entity: ProductPostLink.entryPoint,
|
||||||
fields: ["*", "product.*", "my_custom.*"],
|
fields: ["*", "product.*", "post.*"],
|
||||||
pagination: {
|
pagination: {
|
||||||
take: 5,
|
take: 5,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
@@ -158,8 +172,8 @@ In the object passed to the `graph` method:
|
|||||||
- You pass the `entryPoint` property of the link definition as the value for `entity`. So, Query will retrieve records from the module link's table.
|
- You pass the `entryPoint` property of the link definition as the value for `entity`. So, Query will retrieve records from the module link's table.
|
||||||
- You pass three items to the `field` property:
|
- You pass three items to the `field` property:
|
||||||
- `*` to retrieve the link table's fields. This is useful if the link table has [custom columns](../custom-columns/page.mdx).
|
- `*` to retrieve the link table's fields. This is useful if the link table has [custom columns](../custom-columns/page.mdx).
|
||||||
- `product.*` to retrieve the fields of a product record linked to a `MyCustom` record.
|
- `product.*` to retrieve the fields of a product record linked to a `Post` record.
|
||||||
- `my_custom.*` to retrieve the fields of a `MyCustom` record linked to a product record.
|
- `post.*` to retrieve the fields of a `Post` record linked to a product record.
|
||||||
|
|
||||||
You can then apply any [filters](#apply-filters) or [pagination configurations](#apply-pagination).
|
You can then apply any [filters](#apply-filters) or [pagination configurations](#apply-pagination).
|
||||||
|
|
||||||
@@ -169,58 +183,173 @@ The returned `data` is similar to the following:
|
|||||||
[{
|
[{
|
||||||
"id": "123",
|
"id": "123",
|
||||||
"product_id": "prod_123",
|
"product_id": "prod_123",
|
||||||
"my_custom_id": "123",
|
"post_id": "123",
|
||||||
"product": {
|
"product": {
|
||||||
"id": "prod_123",
|
"id": "prod_123",
|
||||||
// other product fields...
|
// other product fields...
|
||||||
},
|
},
|
||||||
"my_custom": {
|
"post": {
|
||||||
"id": "123",
|
"id": "123",
|
||||||
// other my_custom fields...
|
// other post fields...
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Apply Filters
|
## Apply Filters
|
||||||
|
|
||||||
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
|
```ts highlights={[["4"], ["5"], ["6"]]}
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "title"],
|
||||||
filters: {
|
filters: {
|
||||||
id: [
|
id: "post_123",
|
||||||
"mc_01HWSVWR4D2XVPQ06DQ8X9K7AX",
|
|
||||||
"mc_01HWSVWK3KYHKQEE6QGS2JC3FX",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
The `query.graph` function accepts a `filters` property. You can use this property to filter retrieved records.
|
The `query.graph` function accepts a `filters` property. You can use this property to filter retrieved records.
|
||||||
|
|
||||||
In the example above, you filter the `my_custom` records by multiple IDs.
|
In the example above, you filter the `post` records by the ID `post_123`.
|
||||||
|
|
||||||
|
You can also filter by multiple values of a property. For example:
|
||||||
|
|
||||||
|
```ts highlights={[["4"], ["5"], ["6"], ["7"], ["8"], ["9"]]}
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
id: [
|
||||||
|
"post_123",
|
||||||
|
"post_321",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, you filter the `post` records by multiple IDs.
|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
|
|
||||||
Filters don't apply on fields of linked data models from other modules.
|
Filters don't apply on fields of linked data models from other modules. Refer to the [Retrieve Linked Records](#retrieve-linked-records) section for an alternative solution.
|
||||||
|
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
|
### Advanced Query Filters
|
||||||
|
|
||||||
|
Under the hood, Query uses the `listX` (`listPosts`) method of the data model's module's service to retrieve records. This method accepts a filter object that can be used to filter records.
|
||||||
|
|
||||||
|
Those filters don't just allow you to filter by exact values. You can also filter by properties that don't match a value, match multiple values, and other filter types.
|
||||||
|
|
||||||
|
Refer to the [Service Factory Reference](!resources!/service-factory-reference/tips/filtering) for examples of advanced filters. The following sections provide some quick examples.
|
||||||
|
|
||||||
|
#### Filter by Not Matching a Value
|
||||||
|
|
||||||
|
```ts highlights={[["4"], ["5"], ["6"], ["7"], ["8"]]}
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
title: {
|
||||||
|
$ne: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that have a title are retrieved.
|
||||||
|
|
||||||
|
#### Filter by Not Matching Multiple Values
|
||||||
|
|
||||||
|
```ts highlights={[["4"], ["5"], ["6"], ["7"], ["8"]]}
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
title: {
|
||||||
|
$nin: ["My Post", "Another Post"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that don't have the title `My Post` or `Another Post` are retrieved.
|
||||||
|
|
||||||
|
#### Filter by a Range
|
||||||
|
|
||||||
|
```ts highlights={[["10"], ["11"], ["12"], ["13"], ["14"], ["15"]]}
|
||||||
|
const startToday = new Date()
|
||||||
|
startToday.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
|
const endToday = new Date()
|
||||||
|
endToday.setHours(23, 59, 59, 59)
|
||||||
|
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
published_at: {
|
||||||
|
$gt: startToday,
|
||||||
|
$lt: endToday,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that were published today are retrieved.
|
||||||
|
|
||||||
|
#### Filter Text by Like Value
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
|
||||||
|
This filter only applies to text-like properties, including `text`, `id`, and `enum` properties.
|
||||||
|
|
||||||
|
</Note>
|
||||||
|
|
||||||
|
```ts highlights={[["4"], ["5"], ["6"], ["7"], ["8"]]}
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
title: {
|
||||||
|
$like: "%My%",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that have the word `My` in their title are retrieved.
|
||||||
|
|
||||||
|
#### Filter a Relation's Property
|
||||||
|
|
||||||
|
```ts highlights={[["4"], ["5"], ["6"], ["7"], ["8"]]}
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
author: {
|
||||||
|
name: "John",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
While it's not possible to filter by a linked data model's property, you can filter by a relation's property (that is, the property of a related data model that is defined in the same module).
|
||||||
|
|
||||||
|
In the example above, only posts that have an author with the name `John` are retrieved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Apply Pagination
|
## Apply Pagination
|
||||||
|
|
||||||
```ts highlights={[["8", "skip", "The number of records to skip before fetching the results."], ["9", "take", "The number of records to fetch."]]}
|
```ts highlights={[["8", "skip", "The number of records to skip before fetching the results."], ["9", "take", "The number of records to fetch."]]}
|
||||||
const {
|
const {
|
||||||
data: myCustoms,
|
data: posts,
|
||||||
metadata: { count, take, skip } = {},
|
metadata: { count, take, skip } = {},
|
||||||
} = await query.graph({
|
} = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "title"],
|
||||||
pagination: {
|
pagination: {
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 10,
|
take: 10,
|
||||||
@@ -258,9 +387,9 @@ When you provide the pagination fields, the `query.graph` method's returned obje
|
|||||||
### Sort Records
|
### Sort Records
|
||||||
|
|
||||||
```ts highlights={[["5"], ["6"], ["7"]]}
|
```ts highlights={[["5"], ["6"], ["7"]]}
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "title"],
|
||||||
pagination: {
|
pagination: {
|
||||||
order: {
|
order: {
|
||||||
name: "DESC",
|
name: "DESC",
|
||||||
@@ -284,6 +413,72 @@ The `order` property is an object whose keys are property names, and values are
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Configure Query to Throw Errors
|
||||||
|
|
||||||
|
By default, if Query doesn't find records matching your query, it returns an empty array. You can add option to configure Query to throw an error when no records are found.
|
||||||
|
|
||||||
|
The `query.graph` method accepts as a second parameter an object that can have a `throwIfKeyNotFound` property. Its value is a boolean indicating whether to throw an error if no record is found when filtering by IDs. By default, it's `false`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title"],
|
||||||
|
filters: {
|
||||||
|
id: "post_123",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
throwIfKeyNotFound: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, if no post is found with the ID `post_123`, Query will throw an error. This is useful to stop execution when a record is expected to exist.
|
||||||
|
|
||||||
|
### Throw Error on Related Data Model
|
||||||
|
|
||||||
|
The `throwIfKeyNotFound` option can also be used to throw an error if the ID of a related data model's record (in the same module) is passed in the filters, and the related record doesn't exist.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["id", "title", "author.*"],
|
||||||
|
filters: {
|
||||||
|
id: "post_123",
|
||||||
|
author_id: "author_123",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
throwIfKeyNotFound: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, Query throws an error either if no post is found with the ID `post_123` or if its found but its author ID isn't `author_123`.
|
||||||
|
|
||||||
|
In the above example, it's assumed that a post belongs to an author, so it has an `author_id` property. However, this also works in the opposite case, where an author has many posts.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { data: posts } = await query.graph({
|
||||||
|
entity: "author",
|
||||||
|
fields: ["id", "name", "posts.*"],
|
||||||
|
filters: {
|
||||||
|
id: "author_123",
|
||||||
|
posts: {
|
||||||
|
id: "post_123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
throwIfKeyNotFound: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, Query throws an error if no author is found with the ID `author_123` or if the author is found but doesn't have a post with the ID `post_123`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Request Query Configurations
|
## Request Query Configurations
|
||||||
|
|
||||||
For API routes that retrieve a single or list of resources, Medusa provides a `validateAndTransformQuery` middleware that:
|
For API routes that retrieve a single or list of resources, Medusa provides a `validateAndTransformQuery` middleware that:
|
||||||
@@ -317,7 +512,7 @@ export default defineMiddlewares({
|
|||||||
{
|
{
|
||||||
defaults: [
|
defaults: [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"title",
|
||||||
"products.*",
|
"products.*",
|
||||||
],
|
],
|
||||||
isList: true,
|
isList: true,
|
||||||
@@ -375,12 +570,12 @@ export const GET = async (
|
|||||||
) => {
|
) => {
|
||||||
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
|
||||||
|
|
||||||
const { data: myCustoms } = await query.graph({
|
const { data: posts } = await query.graph({
|
||||||
entity: "my_custom",
|
entity: "post",
|
||||||
...req.queryConfig,
|
...req.queryConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ my_customs: myCustoms })
|
res.json({ posts: posts })
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -394,10 +589,10 @@ To test it out, start your Medusa application and send a `GET` request to the `/
|
|||||||
|
|
||||||
```json title="Returned Data"
|
```json title="Returned Data"
|
||||||
{
|
{
|
||||||
"my_customs": [
|
"posts": [
|
||||||
{
|
{
|
||||||
"id": "123",
|
"id": "123",
|
||||||
"name": "test"
|
"title": "test"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export default defineLink(
|
|||||||
},
|
},
|
||||||
ProductModule.linkable.product,
|
ProductModule.linkable.product,
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -76,8 +76,8 @@ const { result } = await query.graph({
|
|||||||
entity: "post",
|
entity: "post",
|
||||||
fields: ["id", "product.*"],
|
fields: ["id", "product.*"],
|
||||||
filters: {
|
filters: {
|
||||||
id: "post_123"
|
id: "post_123",
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ export default defineLink(
|
|||||||
primaryKey: "product_id",
|
primaryKey: "product_id",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -133,8 +133,8 @@ const { result } = await query.graph({
|
|||||||
entity: "product",
|
entity: "product",
|
||||||
fields: ["id", "post.*"],
|
fields: ["id", "post.*"],
|
||||||
filters: {
|
filters: {
|
||||||
id: "prod_123"
|
id: "prod_123",
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ export default defineLink(
|
|||||||
},
|
},
|
||||||
ProductModule.linkable.product,
|
ProductModule.linkable.product,
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -229,7 +229,7 @@ export default defineLink(
|
|||||||
},
|
},
|
||||||
ProductModule.linkable.product,
|
ProductModule.linkable.product,
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -276,7 +276,7 @@ export default defineLink(
|
|||||||
primaryKey: "product_id",
|
primaryKey: "product_id",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -343,14 +343,14 @@ export default defineLink(
|
|||||||
{
|
{
|
||||||
linkable: ProductModule.linkable.product,
|
linkable: ProductModule.linkable.product,
|
||||||
field: "id",
|
field: "id",
|
||||||
isList: true
|
isList: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...BlogModule.linkable.post.id,
|
...BlogModule.linkable.post.id,
|
||||||
primaryKey: "product_id"
|
primaryKey: "product_id",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -444,14 +444,14 @@ import { CMS_MODULE } from "../modules/cms"
|
|||||||
export default defineLink(
|
export default defineLink(
|
||||||
{
|
{
|
||||||
linkable: ProductModule.linkable.product,
|
linkable: ProductModule.linkable.product,
|
||||||
field: "id"
|
field: "id",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
linkable: {
|
linkable: {
|
||||||
serviceName: CMS_MODULE,
|
serviceName: CMS_MODULE,
|
||||||
alias: "cms_post",
|
alias: "cms_post",
|
||||||
primaryKey: "product_id",
|
primaryKey: "product_id",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ So, to run database queries in a service:
|
|||||||
For example, in your service, add the following methods:
|
For example, in your service, add the following methods:
|
||||||
|
|
||||||
export const methodsHighlight = [
|
export const methodsHighlight = [
|
||||||
["12", "getCount", "Retrieves the number of records in `my_custom` using the `count` method."],
|
["13", "getCount", "Retrieves the number of records in `my_custom` using the `count` method."],
|
||||||
["19", "getCountSql", "Retrieves the number of records in `my_custom` using the `execute` method."]
|
["20", "getCountSql", "Retrieves the number of records in `my_custom` using the `execute` method."]
|
||||||
]
|
]
|
||||||
|
|
||||||
```ts highlights={methodsHighlight}
|
```ts highlights={methodsHighlight}
|
||||||
@@ -38,7 +38,8 @@ import {
|
|||||||
InjectManager,
|
InjectManager,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
import { SqlEntityManager } from "@mikro-orm/knex"
|
import { Context } from "@medusajs/framework/types"
|
||||||
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
// ...
|
// ...
|
||||||
@@ -46,19 +47,19 @@ class BlogModuleService {
|
|||||||
@InjectManager()
|
@InjectManager()
|
||||||
async getCount(
|
async getCount(
|
||||||
@MedusaContext() sharedContext?: Context<EntityManager>
|
@MedusaContext() sharedContext?: Context<EntityManager>
|
||||||
): Promise<number> {
|
): Promise<number | undefined> {
|
||||||
return await sharedContext.manager.count("my_custom")
|
return await sharedContext?.manager?.count("my_custom")
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectManager()
|
@InjectManager()
|
||||||
async getCountSql(
|
async getCountSql(
|
||||||
@MedusaContext() sharedContext?: Context<EntityManager>
|
@MedusaContext() sharedContext?: Context<EntityManager>
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const data = await sharedContext.manager.execute(
|
const data = await sharedContext?.manager?.execute(
|
||||||
"SELECT COUNT(*) as num FROM my_custom"
|
"SELECT COUNT(*) as num FROM my_custom"
|
||||||
)
|
)
|
||||||
|
|
||||||
return parseInt(data[0].num)
|
return parseInt(data?.[0].num || 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -115,8 +116,8 @@ class BlogModuleService {
|
|||||||
},
|
},
|
||||||
@MedusaContext() sharedContext?: Context<EntityManager>
|
@MedusaContext() sharedContext?: Context<EntityManager>
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const transactionManager = sharedContext.transactionManager
|
const transactionManager = sharedContext?.transactionManager
|
||||||
await transactionManager.nativeUpdate(
|
await transactionManager?.nativeUpdate(
|
||||||
"my_custom",
|
"my_custom",
|
||||||
{
|
{
|
||||||
id: input.id,
|
id: input.id,
|
||||||
@@ -127,7 +128,7 @@ class BlogModuleService {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// retrieve again
|
// retrieve again
|
||||||
const updatedRecord = await transactionManager.execute(
|
const updatedRecord = await transactionManager?.execute(
|
||||||
`SELECT * FROM my_custom WHERE id = '${input.id}'`
|
`SELECT * FROM my_custom WHERE id = '${input.id}'`
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -178,10 +179,22 @@ For example, the `update` method could be changed to the following:
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// other imports...
|
// other imports...
|
||||||
|
import {
|
||||||
|
InjectManager,
|
||||||
|
InjectTransactionManager,
|
||||||
|
MedusaContext,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
import { EntityManager } from "@mikro-orm/knex"
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
// ...
|
// ...
|
||||||
|
@InjectTransactionManager()
|
||||||
|
protected async update_(
|
||||||
|
// ...
|
||||||
|
): Promise<any> {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
@InjectManager()
|
@InjectManager()
|
||||||
async update(
|
async update(
|
||||||
input: {
|
input: {
|
||||||
@@ -192,12 +205,14 @@ class BlogModuleService {
|
|||||||
) {
|
) {
|
||||||
const newData = await this.update_(input, sharedContext)
|
const newData = await this.update_(input, sharedContext)
|
||||||
|
|
||||||
await sendNewDataToSystem(newData)
|
// example method that sends data to another system
|
||||||
|
await this.sendNewDataToSystem(newData)
|
||||||
|
|
||||||
return newData
|
return newData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case, only the `update_` method is wrapped in a transaction. The returned value `newData` holds the committed result, which can be used for other operations, such as passed to a `sendNewDataToSystem` method.
|
In this case, only the `update_` method is wrapped in a transaction. The returned value `newData` holds the committed result, which can be used for other operations, such as passed to a `sendNewDataToSystem` method.
|
||||||
|
|
||||||
### Using Methods in Transactional Methods
|
### Using Methods in Transactional Methods
|
||||||
@@ -208,6 +223,11 @@ For example:
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// other imports...
|
// other imports...
|
||||||
|
import {
|
||||||
|
InjectTransactionManager,
|
||||||
|
MedusaContext,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
import { EntityManager } from "@mikro-orm/knex"
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
@@ -343,7 +363,7 @@ class BlogModuleService {
|
|||||||
return updatedRecord
|
return updatedRecord
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transaction: sharedContext.transactionManager,
|
transaction: sharedContext?.transactionManager,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -382,6 +402,12 @@ The second parameter of the `baseRepository_.transaction` method is an object of
|
|||||||
```ts highlights={[["16"]]}
|
```ts highlights={[["16"]]}
|
||||||
// other imports...
|
// other imports...
|
||||||
import { EntityManager } from "@mikro-orm/knex"
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
import {
|
||||||
|
InjectTransactionManager,
|
||||||
|
MedusaContext,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
// ...
|
// ...
|
||||||
@@ -398,7 +424,7 @@ class BlogModuleService {
|
|||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transaction: sharedContext.transactionManager,
|
transaction: sharedContext?.transactionManager,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -414,6 +440,12 @@ class BlogModuleService {
|
|||||||
|
|
||||||
```ts highlights={[["19"]]}
|
```ts highlights={[["19"]]}
|
||||||
// other imports...
|
// other imports...
|
||||||
|
import {
|
||||||
|
InjectTransactionManager,
|
||||||
|
MedusaContext,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
import { IsolationLevel } from "@mikro-orm/core"
|
import { IsolationLevel } from "@mikro-orm/core"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
@@ -442,6 +474,14 @@ class BlogModuleService {
|
|||||||
- If `transaction` is provided and this is disabled, the manager in `transaction` is re-used.
|
- If `transaction` is provided and this is disabled, the manager in `transaction` is re-used.
|
||||||
|
|
||||||
```ts highlights={[["16"]]}
|
```ts highlights={[["16"]]}
|
||||||
|
// other imports...
|
||||||
|
import {
|
||||||
|
InjectTransactionManager,
|
||||||
|
MedusaContext,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
|
import { Context } from "@medusajs/framework/types"
|
||||||
|
import { EntityManager } from "@mikro-orm/knex"
|
||||||
|
|
||||||
class BlogModuleService {
|
class BlogModuleService {
|
||||||
// ...
|
// ...
|
||||||
@InjectTransactionManager()
|
@InjectTransactionManager()
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const generatedEditDates = {
|
|||||||
"app/learn/fundamentals/events-and-subscribers/emit-event/page.mdx": "2025-03-18T15:09:40.243Z",
|
"app/learn/fundamentals/events-and-subscribers/emit-event/page.mdx": "2025-03-18T15:09:40.243Z",
|
||||||
"app/learn/fundamentals/workflows/conditions/page.mdx": "2025-01-27T08:45:19.027Z",
|
"app/learn/fundamentals/workflows/conditions/page.mdx": "2025-01-27T08:45:19.027Z",
|
||||||
"app/learn/fundamentals/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00",
|
"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/admin/page.mdx": "2025-03-21T08:25:13.754Z",
|
||||||
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2025-03-18T08:02:14.085Z",
|
"app/learn/fundamentals/workflows/long-running-workflow/page.mdx": "2025-03-18T08:02:14.085Z",
|
||||||
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2025-02-12T13:55:33.437Z",
|
"app/learn/fundamentals/workflows/constructor-constraints/page.mdx": "2025-02-12T13:55:33.437Z",
|
||||||
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2025-03-18T08:00:44.980Z",
|
"app/learn/fundamentals/data-models/write-migration/page.mdx": "2025-03-18T08:00:44.980Z",
|
||||||
@@ -68,8 +68,8 @@ export const generatedEditDates = {
|
|||||||
"app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-03-11T13:29:54.752Z",
|
"app/learn/fundamentals/module-links/custom-columns/page.mdx": "2025-03-11T13:29:54.752Z",
|
||||||
"app/learn/fundamentals/module-links/directions/page.mdx": "2025-03-17T12:52:06.161Z",
|
"app/learn/fundamentals/module-links/directions/page.mdx": "2025-03-17T12:52:06.161Z",
|
||||||
"app/learn/fundamentals/module-links/page.mdx": "2025-03-11T13:39:14.345Z",
|
"app/learn/fundamentals/module-links/page.mdx": "2025-03-11T13:39:14.345Z",
|
||||||
"app/learn/fundamentals/module-links/query/page.mdx": "2025-03-11T15:35:10.605Z",
|
"app/learn/fundamentals/module-links/query/page.mdx": "2025-03-21T09:14:54.943Z",
|
||||||
"app/learn/fundamentals/modules/db-operations/page.mdx": "2025-03-18T15:10:57.351Z",
|
"app/learn/fundamentals/modules/db-operations/page.mdx": "2025-03-21T09:21:46.901Z",
|
||||||
"app/learn/fundamentals/modules/multiple-services/page.mdx": "2025-03-18T15:11:44.632Z",
|
"app/learn/fundamentals/modules/multiple-services/page.mdx": "2025-03-18T15:11:44.632Z",
|
||||||
"app/learn/fundamentals/modules/page.mdx": "2025-03-18T07:51:09.049Z",
|
"app/learn/fundamentals/modules/page.mdx": "2025-03-18T07:51:09.049Z",
|
||||||
"app/learn/debugging-and-testing/instrumentation/page.mdx": "2025-02-24T08:12:53.132Z",
|
"app/learn/debugging-and-testing/instrumentation/page.mdx": "2025-02-24T08:12:53.132Z",
|
||||||
@@ -117,6 +117,6 @@ export const generatedEditDates = {
|
|||||||
"app/learn/configurations/medusa-config/page.mdx": "2025-03-11T14:27:04.528Z",
|
"app/learn/configurations/medusa-config/page.mdx": "2025-03-11T14:27:04.528Z",
|
||||||
"app/learn/configurations/ts-aliases/page.mdx": "2025-02-11T16:57:46.683Z",
|
"app/learn/configurations/ts-aliases/page.mdx": "2025-02-11T16:57:46.683Z",
|
||||||
"app/learn/production/worker-mode/page.mdx": "2025-03-11T15:21:50.906Z",
|
"app/learn/production/worker-mode/page.mdx": "2025-03-11T15:21:50.906Z",
|
||||||
"app/learn/fundamentals/module-links/read-only/page.mdx": "2025-03-17T14:18:29.924Z",
|
"app/learn/fundamentals/module-links/read-only/page.mdx": "2025-03-21T09:14:54.944Z",
|
||||||
"app/learn/fundamentals/data-models/properties/page.mdx": "2025-03-18T07:57:17.826Z"
|
"app/learn/fundamentals/data-models/properties/page.mdx": "2025-03-18T07:57:17.826Z"
|
||||||
}
|
}
|
||||||
+16024
-15671
File diff suppressed because it is too large.
Load diff
@@ -2,7 +2,8 @@
|
|||||||
sidebar_label: "Vercel"
|
sidebar_label: "Vercel"
|
||||||
---
|
---
|
||||||
|
|
||||||
import { Prerequisites } from "docs-ui"
|
import RewritesError from "../../../troubleshooting/_sections/storefront/rewrites.mdx"
|
||||||
|
import { Prerequisites, DetailsList } from "docs-ui"
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: `Deploy Medusa Next.js to Vercel`,
|
title: `Deploy Medusa Next.js to Vercel`,
|
||||||
@@ -143,3 +144,12 @@ Once the redeployment is done, test out the storefront by going to its URL. Try
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
If you’re running into issues in your storefront, find the logs in your Vercel project’s dashboard under the Logs tab.
|
If you’re running into issues in your storefront, find the logs in your Vercel project’s dashboard under the Logs tab.
|
||||||
|
|
||||||
|
<DetailsList
|
||||||
|
sections={[
|
||||||
|
{
|
||||||
|
title: "Login Page Error",
|
||||||
|
content: <RewritesError />
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
@@ -337,7 +337,7 @@ export default defineLink(
|
|||||||
},
|
},
|
||||||
ProductModule.linkable.product,
|
ProductModule.linkable.product,
|
||||||
{
|
{
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
@@ -1610,7 +1610,7 @@ export default defineMiddlewares({
|
|||||||
"first_name",
|
"first_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
"content",
|
"content",
|
||||||
"created_at"
|
"created_at",
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -24,13 +24,29 @@ The `list` method is used in the example snippets of this reference, but you can
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
const posts = await postModuleService.listPosts({
|
const posts = await postModuleService.listPosts({
|
||||||
name: "My Post 2",
|
title: "My Post 2",
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
If you pass a property with its value, only records whose properties exactly match the value are selected.
|
If you pass a property with its value, only records whose properties exactly match the value are selected.
|
||||||
|
|
||||||
In the example above, only posts having the name `My Post 2` are retrieved.
|
In the example above, only posts having the title `My Post 2` are retrieved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Doesn't Match Exact Value
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
title: {
|
||||||
|
$ne: "My Post",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
To find records with a property that doesn't match a value, pass an object with a `$ne` property. Its value is the value that a record's property shouldn't match.
|
||||||
|
|
||||||
|
In the example above, only posts that don't have the title `My Post` are retrieved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -51,11 +67,11 @@ In the example above, only posts having either `50` or `100` views are retrieved
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Don't Match Values
|
## Don't Match Multiple Values
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const posts = await postModuleService.listPosts({
|
const posts = await postModuleService.listPosts({
|
||||||
name: {
|
title: {
|
||||||
$nin: [
|
$nin: [
|
||||||
"My Post",
|
"My Post",
|
||||||
],
|
],
|
||||||
@@ -65,7 +81,7 @@ const posts = await postModuleService.listPosts({
|
|||||||
|
|
||||||
To find records with a property that doesn't match one or more values, pass an object with a `$nin` property. Its value is an array of multiple values that a record's property shouldn't match.
|
To find records with a property that doesn't match one or more values, pass an object with a `$nin` property. Its value is an array of multiple values that a record's property shouldn't match.
|
||||||
|
|
||||||
In the example above, only posts that don't have the name `My Post` are retrieved.
|
In the example above, only posts that don't have the title `My Post` are retrieved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -73,13 +89,13 @@ In the example above, only posts that don't have the name `My Post` are retrieve
|
|||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
|
|
||||||
This filter only applies to text-like properties, including `id` and `enum` properties.
|
This filter only applies to text-like properties, including `text`, `id`, and `enum` properties.
|
||||||
|
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const posts = await postModuleService.listPosts({
|
const posts = await postModuleService.listPosts({
|
||||||
name: {
|
title: {
|
||||||
$like: "My%",
|
$like: "My%",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -87,7 +103,37 @@ const posts = await postModuleService.listPosts({
|
|||||||
|
|
||||||
To perform a `like` filter on a record's property, set the property's value to an object with a `$like` property. Its value is the string to use when applying the `like` filter.
|
To perform a `like` filter on a record's property, set the property's value to an object with a `$like` property. Its value is the string to use when applying the `like` filter.
|
||||||
|
|
||||||
The example above matches all posts whose name starts with `My`.
|
The example above matches all posts whose title starts with `My`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Filter by Null or Not Null
|
||||||
|
|
||||||
|
To retrieve records with a property that is `null`, set the property's value to `null`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
published_at: null,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that have a `null` publish date are retrieved.
|
||||||
|
|
||||||
|
On the other hand, to retrieve records with a property that isn't `null`, set the property's value to an object with a `$ne` property.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
published_at: {
|
||||||
|
$ne: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts that have a publish date are retrieved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -137,6 +183,19 @@ The `dateTime` property also stores the time. So, when matching for an exact day
|
|||||||
|
|
||||||
In this example, you retrieve the current date twice: once to set its time to `00:00:00`, and another to set its time `23:59:59`. Then, you retrieve posts whose `published_at` property is between `00:00:00` and `23:59:59` of today.
|
In this example, you retrieve the current date twice: once to set its time to `00:00:00`, and another to set its time `23:59:59`. Then, you retrieve posts whose `published_at` property is between `00:00:00` and `23:59:59` of today.
|
||||||
|
|
||||||
|
### Example: Range Filter on Number Property
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
views: {
|
||||||
|
$gte: 50,
|
||||||
|
$lte: 100,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, only posts with `views` between `50` and `100` are retrieved.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Apply Or Condition
|
## Apply Or Condition
|
||||||
@@ -145,7 +204,7 @@ In this example, you retrieve the current date twice: once to set its time to `0
|
|||||||
const posts = await postModuleService.listPosts({
|
const posts = await postModuleService.listPosts({
|
||||||
$or: [
|
$or: [
|
||||||
{
|
{
|
||||||
name: "My Post",
|
title: "My Post",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
published_at: {
|
published_at: {
|
||||||
@@ -158,4 +217,60 @@ const posts = await postModuleService.listPosts({
|
|||||||
|
|
||||||
To use an `or` condition, pass to the filter object the `$or` property, whose value is an array of filters.
|
To use an `or` condition, pass to the filter object the `$or` property, whose value is an array of filters.
|
||||||
|
|
||||||
In the example above, posts whose name is `My Post` or their `published_at` date is less than the current date and time are retrieved.
|
In the example above, posts whose title is `My Post` or their `published_at` date is less than the current date and time are retrieved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Apply And Condition
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
$and: [
|
||||||
|
{
|
||||||
|
title: "My Post",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
published_at: {
|
||||||
|
$lt: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
To use an `and` condition, pass to the filter object the `$and` property, whose value is an array of filters.
|
||||||
|
|
||||||
|
In the example above, only posts whose title is `My Post` and their `published_at` date is less than the current date and time are retrieved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Complex Filters Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const posts = await postModuleService.listPosts({
|
||||||
|
$or: [
|
||||||
|
{
|
||||||
|
$and: [
|
||||||
|
{ views: { $gte: 50 } },
|
||||||
|
{
|
||||||
|
published_at: {
|
||||||
|
$gte: new Date(new Date().getFullYear(), 0, 1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: {
|
||||||
|
$like: "%Featured%",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above, posts are retrieved if they meet either of the following conditions:
|
||||||
|
|
||||||
|
1. The post has at least `50` views and was published after the beginning of the current year.
|
||||||
|
2. The post's title contains the word `Featured`.
|
||||||
|
|
||||||
|
By combining `and` and `or` conditions, you can create complex filters to retrieve records that meet specific criteria.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
If you see the following error in the Medusa Admin's console:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Blocked request. This host (X) is not allowed. To allow this host, add X to server.allowedHosts in vite.config.js.
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `X` is the host that's being blocked. For example, `example.com`.
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error occurs if you deploy Medusa but are using development mode (`NODE_ENV=development`). This can happen accidentally or unintentionally, but Medusa defaults `NODE_ENV` to `production`.
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
### Option 1: Use Production Mode
|
||||||
|
|
||||||
|
To resolve this error, ensure that you're running Medusa in production mode. You can set the `NODE_ENV` environment variable to `production` when starting Medusa:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NODE_ENV=production
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: Allow the Host
|
||||||
|
|
||||||
|
If you intentionally want to use development mode in your deployed Medusa instance, you can allow the host that's being blocked using the `admin.vite` configuration in `medusa-config.ts`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts title="medusa-config.ts"
|
||||||
|
module.exports = defineConfig({
|
||||||
|
// ...
|
||||||
|
admin: {
|
||||||
|
vite: () => {
|
||||||
|
return {
|
||||||
|
server: {
|
||||||
|
allowedHosts: [".example.com"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, you allow the host `example.com` to access the Medusa Admin. Make sure that when you replace `example.com` with your actual host, you include the leading `.` before the domain name.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Environment Variables](!docs!/learn/fundamentals/environment-variables)
|
||||||
|
- [admin.vite Configuration](!docs!/learn/configurations/medusa-config#vite)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
If you send a request to an API route and receive the following error:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "invalid_data",
|
||||||
|
"message": "Invalid request: Unrecognized fields: 'additional_data'"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why this Error Occured
|
||||||
|
|
||||||
|
This error occurs when you send the `additional_data` request body parameter to a route that doesn't support it.
|
||||||
|
|
||||||
|
The [Additional Data property](https://docs.medusajs.com/learn/fundamentals/api-routes/additional-data) is useful to pass custom data to an API route, but it's not supported by all API routes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
For the list of API routes that support passing `additional_data`, refer to the [Additional Data documentation](https://docs.medusajs.com/learn/fundamentals/api-routes/additional-data).
|
||||||
|
|
||||||
|
If the route you need isn't on the list, you have to create a custom API route with your desired functionality.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
If you get the following error after creating a new data model in your Medusa application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
error: Error: Cannot define field(s) "created_at,updated_at,deleted_at" as they are implicitly defined on every model
|
||||||
|
```
|
||||||
|
|
||||||
|
The error may include the three fields, or only some of them, based on which fields you're trying to define in the data model.
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error occurs because you're trying to define the `created_at`, `updated_at`, or `deleted_at` properties on a new data model. These properties are implicitly defined on every data model in Medusa and can't be redefined.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
To resolve this error, remove the `created_at`, `updated_at`, and `deleted_at` properties from your data model definition. You'll still be able to use these properties in your application, but you can't redefine them in your data models.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Data Model's Default Properties](!docs!/learn/fundamentals/data-models/properties#data-models-default-properties)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
If you get the following error in your Medusa application's terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Trying to query by not existing property LinkModel.X.
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `X` is the name of a data model. For example, `LinkModel.cart`.
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error occurs when you're using Query and you're trying to filter by a linked module, which isn't allowed.
|
||||||
|
|
||||||
|
For example, assuming you have a `Post` data model and you linked it to the `Cart` data model, this isn't allowed:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { data } = await query.graph({
|
||||||
|
entity: "post",
|
||||||
|
fields: ["*"],
|
||||||
|
filter: {
|
||||||
|
cart: {
|
||||||
|
id: "cart_123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
You can't filter your custom `post` data model by the ID of their linked cart.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
You need to query the link's table directly and apply the filters on its ID columns. For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import PostCartLink from "../links/post-cart"
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
const { data } = await query.graph({
|
||||||
|
entity: PostCartLink.entryPoint,
|
||||||
|
fields: ["post.*", "cart.*"],
|
||||||
|
filters: {
|
||||||
|
cart_id: "cart_123",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, you query the `PostCartLink` data model directly and apply the filters to the `cart_id` field, which holds the ID of the cart linked to the post. You'll then only retrieve the posts linked to the cart with the ID `cart_123`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Query](!docs!/learn/fundamentals/module-links/query#apply-filters-and-pagination-on-linked-records)
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
If you get the following error when using Query to retrieve records of your custom data model:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
service.list is not a function
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
To retrieve records of your data model, Query uses the `listX` method of your module's service.
|
||||||
|
|
||||||
|
For example, if you have a Blog Module and you are trying to retrieve posts, Query will try to call the `listPost` method of the Blog Module's service. If it doesn't find the method, it will throw the above error.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
### Option 1: Extend Service Factory
|
||||||
|
|
||||||
|
To resolve this error, make sure that your module's service has a `listX` method that returns the records of your data model.
|
||||||
|
|
||||||
|
This method is generated for you if your service extends `MedusaService`:
|
||||||
|
|
||||||
|
```ts title="src/modules/blog/service.ts"
|
||||||
|
import { MedusaService } from "@medusajs/framework/utils"
|
||||||
|
import Post from "./models/post"
|
||||||
|
|
||||||
|
class BlogModuleService extends MedusaService({
|
||||||
|
Post,
|
||||||
|
}){
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlogModuleService
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, the `listPost` method is generated for you because the `BlogModuleService` extends `MedusaService`.
|
||||||
|
|
||||||
|
### Option 2: Implement the Method
|
||||||
|
|
||||||
|
If your module is returning data from a third-party service, or you have some custom mechanism to define and manage your data models, then you need to implement the `list` or just `list` method in your service.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts title="src/modules/blog/service.ts"
|
||||||
|
type BlogModuleOptions = {
|
||||||
|
apiKey: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class BlogModuleService {
|
||||||
|
private client
|
||||||
|
|
||||||
|
constructor({}, options: BlogModuleOptions) {
|
||||||
|
this.client = new Client(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(
|
||||||
|
filter: {
|
||||||
|
id: string | string[]
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
return this.client.getPosts(filter)
|
||||||
|
/**
|
||||||
|
* Example of returned data:
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* {
|
||||||
|
* "id": "post_123",
|
||||||
|
* "product_id": "prod_321"
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* "id": "post_456",
|
||||||
|
* "product_id": "prod_654"
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Query](!docs!/learn/fundamentals/module-links/query)
|
||||||
|
- [Service Factory documentation](!docs!/learn/fundamentals/modules/service-factory)
|
||||||
|
- [Service Factory reference](../../../service-factory-reference/page.mdx)
|
||||||
|
- [Example: Read-Only Module Link for Virtual Data Models](!docs!/learn/fundamentals/module-links/read-only#example-read-only-module-link-for-virtual-data-models)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
If you send a request to the `/store/products` or `/store/products/:id` API routes and receive the following error in the response:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
{
|
||||||
|
"type": "invalid_data",
|
||||||
|
"message": "Publishable key needs to have a sales channel configured."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error means you passed a valid `x-publishable-api-key` header, but the key does not have a sales channel configured. The sales channel is required to make requests to the `/store/products` and `/store/products/:id` routes, as it's used to retrieve products available in that sales channel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
To resolve this error, you need to add at least one sales channel to your publishable API key. Refer to the [Manage Publishable API Key User Guide](!user-guide!/settings/developer/publishable-api-keys#manage-publishable-api-keys-sales-channels) to learn how to do that.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
If you receive the following error response when you send a request to a `/store` route:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "not_allowed",
|
||||||
|
"message": "Publishable API key required in the request header: x-publishable-api-key. You can manage your keys in settings in the dashboard."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error occurs because the request is missing the `x-publishable-api-key` header. The `x-publishable-api-key` header is required for all requests to the `/store` route.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
To resolve this error, add the `x-publishable-api-key` header to your request. You can find your publishable API key in the [Medusa Admin Dashboard](!user-guide!/settings/developer/publishable-api-keys).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET https://localhost:9000/store/products \
|
||||||
|
-H "x-publishable-api-key: your-publishable-api-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `your-publishable-api-key` is your publishable API key.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [API reference](!api!/store#publishable-api-key)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
The Next.js Starter Storefront uses parallel routes to show account pages. However, there's a [reported error](https://github.com/vercel/next.js/issues/71626) when hosting Next.js with parallel routes on Google's Cloud Run, where the error stops working.
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error occurs because Google Cloud Run decodes chunk URLs, but Next.js expects them to be encoded.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
To resolve the error, add the following rewrites in your Next.js Starter Storefront's `next.config.ts` file:
|
||||||
|
|
||||||
|
```ts title="next.config.ts"
|
||||||
|
const nextConfig = {
|
||||||
|
// ... other config
|
||||||
|
rewrites: async () => {
|
||||||
|
return {
|
||||||
|
beforeFiles: [
|
||||||
|
{
|
||||||
|
source: "/_next/static/chunks/app/:folder*/@login/:path*",
|
||||||
|
destination: "/_next/static/chunks/app/:folder*/%40login/:path*",
|
||||||
|
},
|
||||||
|
// Repeat this pattern if other similar errors occur
|
||||||
|
],
|
||||||
|
afterFiles: [],
|
||||||
|
fallback: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add the rewrite to other parallel routes you have in your application. For example, if you have a `/@dashboard` route, you can add a rewrite for it as well.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
If you get the following error when you start the Medusa application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Error: Step X is already defined in workflow.
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `X` is any step, such as `create-remote-link`.
|
||||||
|
|
||||||
|
## Why this Error Occurred
|
||||||
|
|
||||||
|
This error indicates that you're re-using a step in a workflow, meaning that more than one step in the workflow have the same name.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
To resolve this error, use the `config` method of a step to specify a custom name within the workflow's scope. For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const helloWorkflow = createWorkflow(
|
||||||
|
"hello",
|
||||||
|
() => {
|
||||||
|
const { data: products } = useQueryGraphStep({
|
||||||
|
entity: "product",
|
||||||
|
fields: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
// ✓ No error occurs, the step has a different ID.
|
||||||
|
const { data: customers } = useQueryGraphStep({
|
||||||
|
entity: "customer",
|
||||||
|
fields: ["id"],
|
||||||
|
}).config({ name: "fetch-customers" })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, you use the `config` method on the second `useQueryGraphStep` usage to change its name to `fetch-customers`.
|
||||||
|
|
||||||
|
Make sure to change the name of every usage after the first one in a workflow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Multiple Step Usage in Workflow documentation](https://docs.medusajs.com/learn/fundamentals/workflows/multiple-step-usage)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import AdditionalDataError from "../_sections/api-routes/additional-data.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Unrecognized fields \`additiona_data\` Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<AdditionalDataError />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import DataModelDefaults from "../../_sections/data-models/default-fields.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Can't define fields Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<DataModelDefaults />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import AdminBlockedRequest from "../../_sections/admin/blocked-request.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Blocked Request Error in Medusa Admin`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<AdminBlockedRequest />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import RewritesTroubleshooting from "../_sections/storefront/rewrites.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Next.js Starter Storefront Login Page Error on Google Cloud Run`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<RewritesTroubleshooting />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import NotExistingPropertyError from "../../_sections/query/not-existing-property.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Trying to query by not existing property Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<NotExistingPropertyError />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import ServiceListError from "../../_sections/query/service-list.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `service.list is not a function Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<ServiceListError />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import PakTroubleshooting from "../_sections/storefront/pak.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Publishable API key required Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<PakTroubleshooting />
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import PakScTroubleshooting from "../_sections/storefront/pak-sc.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Publishable API needs to have a sales channel Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<PakScTroubleshooting />
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
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)
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import StepXDefined from "../../_sections/workflows/step-x-defined.mdx"
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: `Step X is already defined in workflow Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
<StepXDefined />
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export const metadata = {
|
||||||
|
title: `Handler for action X Not Found Workflow Error`,
|
||||||
|
}
|
||||||
|
|
||||||
|
# {metadata.title}
|
||||||
|
|
||||||
|
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...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why this Error Occured
|
||||||
|
|
||||||
|
This error occurs if the `when-then` block doesn't return a step's result and doesn't have a name specified.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
when(input, (input) => !input.is_active)
|
||||||
|
.then(() => {
|
||||||
|
console.log("not returning anything")
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
The above `when-then` block doesn't return a step's result, which causes the error.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to Fix it
|
||||||
|
|
||||||
|
You can resolve this error by passing a name as a first parameter of `when`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const result = when(
|
||||||
|
"custom-when-condition",
|
||||||
|
input,
|
||||||
|
(input) => !input.is_active
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
console.log("not returning anything")
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [When-Then documentation](!docs!/learn/fundamentals/workflows/conditions#specify-name-for-when-then)
|
||||||
@@ -102,7 +102,7 @@ export const generatedEditDates = {
|
|||||||
"app/create-medusa-app/page.mdx": "2025-01-16T10:00:25.975Z",
|
"app/create-medusa-app/page.mdx": "2025-01-16T10:00:25.975Z",
|
||||||
"app/deployment/admin/vercel/page.mdx": "2024-10-16T08:10:29.377Z",
|
"app/deployment/admin/vercel/page.mdx": "2024-10-16T08:10:29.377Z",
|
||||||
"app/deployment/medusa-application/railway/page.mdx": "2025-03-11T08:56:02.100Z",
|
"app/deployment/medusa-application/railway/page.mdx": "2025-03-11T08:56:02.100Z",
|
||||||
"app/deployment/storefront/vercel/page.mdx": "2025-01-06T12:19:31.142Z",
|
"app/deployment/storefront/vercel/page.mdx": "2025-03-21T07:19:24.818Z",
|
||||||
"app/deployment/page.mdx": "2024-11-25T14:31:45.277Z",
|
"app/deployment/page.mdx": "2024-11-25T14:31:45.277Z",
|
||||||
"app/integrations/page.mdx": "2025-02-26T11:37:17.771Z",
|
"app/integrations/page.mdx": "2025-02-26T11:37:17.771Z",
|
||||||
"app/medusa-cli/page.mdx": "2024-08-28T11:25:32.382Z",
|
"app/medusa-cli/page.mdx": "2024-08-28T11:25:32.382Z",
|
||||||
@@ -132,7 +132,7 @@ export const generatedEditDates = {
|
|||||||
"app/service-factory-reference/methods/retrieve/page.mdx": "2024-07-31T17:01:33+03:00",
|
"app/service-factory-reference/methods/retrieve/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||||
"app/service-factory-reference/methods/soft-delete/page.mdx": "2024-07-31T17:01:33+03:00",
|
"app/service-factory-reference/methods/soft-delete/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||||
"app/service-factory-reference/methods/update/page.mdx": "2024-07-31T17:01:33+03:00",
|
"app/service-factory-reference/methods/update/page.mdx": "2024-07-31T17:01:33+03:00",
|
||||||
"app/service-factory-reference/tips/filtering/page.mdx": "2024-07-31T17:01:33+03:00",
|
"app/service-factory-reference/tips/filtering/page.mdx": "2025-03-21T08:32:39.125Z",
|
||||||
"app/service-factory-reference/page.mdx": "2024-07-26T14:40:56+00:00",
|
"app/service-factory-reference/page.mdx": "2024-07-26T14:40:56+00:00",
|
||||||
"app/storefront-development/cart/context/page.mdx": "2025-01-06T16:00:34.296Z",
|
"app/storefront-development/cart/context/page.mdx": "2025-01-06T16:00:34.296Z",
|
||||||
"app/storefront-development/cart/create/page.mdx": "2025-02-26T11:44:58.922Z",
|
"app/storefront-development/cart/create/page.mdx": "2025-02-26T11:44:58.922Z",
|
||||||
@@ -5578,7 +5578,6 @@ export const generatedEditDates = {
|
|||||||
"references/types/DmlTypes/types/types.DmlTypes.KnownDataTypes/page.mdx": "2024-12-17T16:57:19.922Z",
|
"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",
|
"references/types/DmlTypes/types/types.DmlTypes.RelationshipTypes/page.mdx": "2024-12-10T14:54:55.435Z",
|
||||||
"app/recipes/commerce-automation/restock-notification/page.mdx": "2025-03-17T07:36:21.511Z",
|
"app/recipes/commerce-automation/restock-notification/page.mdx": "2025-03-17T07:36:21.511Z",
|
||||||
"app/troubleshooting/workflow-errors/page.mdx": "2024-12-11T08:44:36.598Z",
|
|
||||||
"app/integrations/guides/shipstation/page.mdx": "2025-02-26T11:21:46.879Z",
|
"app/integrations/guides/shipstation/page.mdx": "2025-02-26T11:21:46.879Z",
|
||||||
"app/nextjs-starter/guides/customize-stripe/page.mdx": "2024-12-25T14:48:55.877Z",
|
"app/nextjs-starter/guides/customize-stripe/page.mdx": "2024-12-25T14:48:55.877Z",
|
||||||
"references/core_flows/Cart/Workflows_Cart/functions/core_flows.Cart.Workflows_Cart.listShippingOptionsForCartWithPricingWorkflow/page.mdx": "2025-03-04T13:33:40.584Z",
|
"references/core_flows/Cart/Workflows_Cart/functions/core_flows.Cart.Workflows_Cart.listShippingOptionsForCartWithPricingWorkflow/page.mdx": "2025-03-04T13:33:40.584Z",
|
||||||
@@ -6061,5 +6060,15 @@ export const generatedEditDates = {
|
|||||||
"app/nextjs-starter/guides/revalidate-cache/page.mdx": "2025-03-18T08:47:59.628Z",
|
"app/nextjs-starter/guides/revalidate-cache/page.mdx": "2025-03-18T08:47:59.628Z",
|
||||||
"app/storefront-development/cart/totals/page.mdx": "2025-03-18T09:20:59.533Z",
|
"app/storefront-development/cart/totals/page.mdx": "2025-03-18T09:20:59.533Z",
|
||||||
"app/storefront-development/checkout/order-confirmation/page.mdx": "2025-03-18T09:44:14.561Z",
|
"app/storefront-development/checkout/order-confirmation/page.mdx": "2025-03-18T09:44:14.561Z",
|
||||||
"app/how-to-tutorials/tutorials/product-reviews/page.mdx": "2025-03-19T13:00:56.901Z"
|
"app/how-to-tutorials/tutorials/product-reviews/page.mdx": "2025-03-19T13:00:56.901Z",
|
||||||
|
"app/troubleshooting/api-routes/page.mdx": "2025-03-21T07:17:56.248Z",
|
||||||
|
"app/troubleshooting/data-models/default-fields/page.mdx": "2025-03-21T06:59:06.775Z",
|
||||||
|
"app/troubleshooting/medusa-admin/blocked-request/page.mdx": "2025-03-21T06:53:34.854Z",
|
||||||
|
"app/troubleshooting/nextjs-starter-rewrites/page.mdx": "2025-03-21T07:09:08.901Z",
|
||||||
|
"app/troubleshooting/query/filter-linked/page.mdx": "2025-03-21T07:07:51.046Z",
|
||||||
|
"app/troubleshooting/query/service-list/page.mdx": "2025-03-21T07:08:32.825Z",
|
||||||
|
"app/troubleshooting/storefront-missing-pak/page.mdx": "2025-03-21T07:08:52.294Z",
|
||||||
|
"app/troubleshooting/storefront-pak-sc/page.mdx": "2025-03-21T07:08:57.546Z",
|
||||||
|
"app/troubleshooting/workflow-errors/step-x-defined/page.mdx": "2025-03-21T07:09:02.741Z",
|
||||||
|
"app/troubleshooting/workflow-errors/when-then/page.mdx": "2025-03-21T08:35:45.145Z"
|
||||||
}
|
}
|
||||||
@@ -1247,6 +1247,10 @@ export const filesMap = [
|
|||||||
"filePath": "/www/apps/resources/app/tools/page.mdx",
|
"filePath": "/www/apps/resources/app/tools/page.mdx",
|
||||||
"pathname": "/tools"
|
"pathname": "/tools"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/api-routes/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/api-routes"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/cors-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/cors-errors/page.mdx",
|
||||||
"pathname": "/troubleshooting/cors-errors"
|
"pathname": "/troubleshooting/cors-errors"
|
||||||
@@ -1255,6 +1259,10 @@ export const filesMap = [
|
|||||||
"filePath": "/www/apps/resources/app/troubleshooting/create-medusa-app-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/create-medusa-app-errors/page.mdx",
|
||||||
"pathname": "/troubleshooting/create-medusa-app-errors"
|
"pathname": "/troubleshooting/create-medusa-app-errors"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/data-models/default-fields/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/data-models/default-fields"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/database-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/database-errors/page.mdx",
|
||||||
"pathname": "/troubleshooting/database-errors"
|
"pathname": "/troubleshooting/database-errors"
|
||||||
@@ -1279,25 +1287,53 @@ export const filesMap = [
|
|||||||
"filePath": "/www/apps/resources/app/troubleshooting/general-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/general-errors/page.mdx",
|
||||||
"pathname": "/troubleshooting/general-errors"
|
"pathname": "/troubleshooting/general-errors"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/medusa-admin/blocked-request/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/medusa-admin/blocked-request"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/medusa-admin/no-widget-route/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/medusa-admin/no-widget-route/page.mdx",
|
||||||
"pathname": "/troubleshooting/medusa-admin/no-widget-route"
|
"pathname": "/troubleshooting/medusa-admin/no-widget-route"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/nextjs-starter-rewrites/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/nextjs-starter-rewrites"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/page.mdx",
|
||||||
"pathname": "/troubleshooting"
|
"pathname": "/troubleshooting"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/query/filter-linked/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/query/filter-linked"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/query/service-list/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/query/service-list"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/s3/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/s3/page.mdx",
|
||||||
"pathname": "/troubleshooting/s3"
|
"pathname": "/troubleshooting/s3"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/storefront-missing-pak/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/storefront-missing-pak"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/storefront-pak-sc/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/storefront-pak-sc"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/test-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/test-errors/page.mdx",
|
||||||
"pathname": "/troubleshooting/test-errors"
|
"pathname": "/troubleshooting/test-errors"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/app/troubleshooting/workflow-errors/page.mdx",
|
"filePath": "/www/apps/resources/app/troubleshooting/workflow-errors/step-x-defined/page.mdx",
|
||||||
"pathname": "/troubleshooting/workflow-errors"
|
"pathname": "/troubleshooting/workflow-errors/step-x-defined"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filePath": "/www/apps/resources/app/troubleshooting/workflow-errors/when-then/page.mdx",
|
||||||
|
"pathname": "/troubleshooting/workflow-errors/when-then"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filePath": "/www/apps/resources/references/api_key/IApiKeyModuleService/methods/api_key.IApiKeyModuleService.authenticate/page.mdx",
|
"filePath": "/www/apps/resources/references/api_key/IApiKeyModuleService/methods/api_key.IApiKeyModuleService.authenticate/page.mdx",
|
||||||
|
|||||||
@@ -1071,6 +1071,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
|
|||||||
"sort_sidebar": "alphabetize",
|
"sort_sidebar": "alphabetize",
|
||||||
"description": "Learn how to use the Cart Module in your customizations on the Medusa application server.",
|
"description": "Learn how to use the Cart Module in your customizations on the Medusa application server.",
|
||||||
"children": [
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "ref",
|
||||||
|
"title": "Abandoned Cart Notification",
|
||||||
|
"path": "https://docs.medusajs.com/resources/how-to-tutorials/tutorials/abandoned-cart",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"loaded": true,
|
"loaded": true,
|
||||||
"isPathHref": true,
|
"isPathHref": true,
|
||||||
|
|||||||
@@ -50,7 +50,24 @@ const generatedgeneratedTroubleshootingSidebarSidebar = {
|
|||||||
"loaded": true,
|
"loaded": true,
|
||||||
"isPathHref": true,
|
"isPathHref": true,
|
||||||
"type": "category",
|
"type": "category",
|
||||||
"title": "Medusa Application",
|
"title": "Upgrade",
|
||||||
|
"initialOpen": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/errors-after-upgrading",
|
||||||
|
"title": "Errors After Upgrading",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "category",
|
||||||
|
"title": "Framework",
|
||||||
"initialOpen": true,
|
"initialOpen": true,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
@@ -77,13 +94,45 @@ const generatedgeneratedTroubleshootingSidebarSidebar = {
|
|||||||
"title": "Importing from /dist",
|
"title": "Importing from /dist",
|
||||||
"children": []
|
"children": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "sub-category",
|
||||||
|
"title": "Query",
|
||||||
|
"children": [
|
||||||
{
|
{
|
||||||
"loaded": true,
|
"loaded": true,
|
||||||
"isPathHref": true,
|
"isPathHref": true,
|
||||||
"type": "link",
|
"type": "link",
|
||||||
"path": "/troubleshooting/workflow-errors",
|
"path": "/troubleshooting/query/filter-linked",
|
||||||
"title": "Workflow Errors",
|
"title": "Not Exising Property",
|
||||||
"children": []
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "sub-category",
|
||||||
|
"title": "Workflows",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/workflow-errors/when-then",
|
||||||
|
"title": "Handler Not Found",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/workflow-errors/step-x-defined",
|
||||||
|
"title": "Step Already Defined",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"loaded": true,
|
"loaded": true,
|
||||||
@@ -95,40 +144,6 @@ const generatedgeneratedTroubleshootingSidebarSidebar = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"loaded": true,
|
|
||||||
"isPathHref": true,
|
|
||||||
"type": "category",
|
|
||||||
"title": "Admin Development",
|
|
||||||
"initialOpen": true,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"loaded": true,
|
|
||||||
"isPathHref": true,
|
|
||||||
"type": "link",
|
|
||||||
"path": "/troubleshooting/medusa-admin/no-widget-route",
|
|
||||||
"title": "Widget or Route not Showing",
|
|
||||||
"children": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"loaded": true,
|
|
||||||
"isPathHref": true,
|
|
||||||
"type": "category",
|
|
||||||
"title": "Upgrade",
|
|
||||||
"initialOpen": true,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"loaded": true,
|
|
||||||
"isPathHref": true,
|
|
||||||
"type": "link",
|
|
||||||
"path": "/troubleshooting/errors-after-upgrading",
|
|
||||||
"title": "Errors After Upgrading",
|
|
||||||
"children": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"loaded": true,
|
"loaded": true,
|
||||||
"isPathHref": true,
|
"isPathHref": true,
|
||||||
@@ -162,6 +177,80 @@ const generatedgeneratedTroubleshootingSidebarSidebar = {
|
|||||||
"children": []
|
"children": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "category",
|
||||||
|
"title": "Admin Development",
|
||||||
|
"initialOpen": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/medusa-admin/no-widget-route",
|
||||||
|
"title": "Widget or Route not Showing",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/medusa-admin/blocked-request",
|
||||||
|
"title": "Blocked Request",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "category",
|
||||||
|
"title": "Storefront",
|
||||||
|
"initialOpen": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "sub-category",
|
||||||
|
"title": "Next.js Starter",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/nextjs-starter-rewrites",
|
||||||
|
"title": "Cloud Run Error",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "sub-category",
|
||||||
|
"title": "Publishable API Key Errors",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/storefront-missing-pak",
|
||||||
|
"title": "Missing Publishable API Key",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loaded": true,
|
||||||
|
"isPathHref": true,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/troubleshooting/storefront-pak-sc",
|
||||||
|
"title": "Sales Channels Error",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ const nextConfig = {
|
|||||||
destination: `${process.env.NEXT_PUBLIC_BASE_URL}/learn/configurations/medusa-config`,
|
destination: `${process.env.NEXT_PUBLIC_BASE_URL}/learn/configurations/medusa-config`,
|
||||||
permanent: true,
|
permanent: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
source: "/troubleshooting/workflow-errors",
|
||||||
|
destination: "/troubleshooting/workflow-errors/when-then",
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
outputFileTracingExcludes: {
|
outputFileTracingExcludes: {
|
||||||
|
|||||||
@@ -32,7 +32,19 @@ export const troubleshootingSidebar = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
title: "Medusa Application",
|
title: "Upgrade",
|
||||||
|
initialOpen: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/errors-after-upgrading",
|
||||||
|
title: "Errors After Upgrading",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
title: "Framework",
|
||||||
initialOpen: true,
|
initialOpen: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@@ -50,10 +62,32 @@ export const troubleshootingSidebar = [
|
|||||||
path: "/troubleshooting/dist-imports",
|
path: "/troubleshooting/dist-imports",
|
||||||
title: "Importing from /dist",
|
title: "Importing from /dist",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "sub-category",
|
||||||
|
title: "Query",
|
||||||
|
children: [
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link",
|
||||||
path: "/troubleshooting/workflow-errors",
|
path: "/troubleshooting/query/filter-linked",
|
||||||
title: "Workflow Errors",
|
title: "Not Exising Property",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sub-category",
|
||||||
|
title: "Workflows",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/workflow-errors/when-then",
|
||||||
|
title: "Handler Not Found",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/workflow-errors/step-x-defined",
|
||||||
|
title: "Step Already Defined",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link",
|
||||||
@@ -62,30 +96,6 @@ export const troubleshootingSidebar = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: "category",
|
|
||||||
title: "Admin Development",
|
|
||||||
initialOpen: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: "link",
|
|
||||||
path: "/troubleshooting/medusa-admin/no-widget-route",
|
|
||||||
title: "Widget or Route not Showing",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "category",
|
|
||||||
title: "Upgrade",
|
|
||||||
initialOpen: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: "link",
|
|
||||||
path: "/troubleshooting/errors-after-upgrading",
|
|
||||||
title: "Errors After Upgrading",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
title: "Frontend",
|
title: "Frontend",
|
||||||
@@ -110,4 +120,55 @@ export const troubleshootingSidebar = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
title: "Admin Development",
|
||||||
|
initialOpen: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/medusa-admin/no-widget-route",
|
||||||
|
title: "Widget or Route not Showing",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/medusa-admin/blocked-request",
|
||||||
|
title: "Blocked Request",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
title: "Storefront",
|
||||||
|
initialOpen: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "sub-category",
|
||||||
|
title: "Next.js Starter",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/nextjs-starter-rewrites",
|
||||||
|
title: "Cloud Run Error",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sub-category",
|
||||||
|
title: "Publishable API Key Errors",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/storefront-missing-pak",
|
||||||
|
title: "Missing Publishable API Key",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
path: "/troubleshooting/storefront-pak-sc",
|
||||||
|
title: "Sales Channels Error",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
Reference in new issue
Block a user