docs: general fixes and improvements (#7918)
* docs improvements and changes * updated module definition * modules + dml changes * fix build * fix vale error * fix lint errors * fixes to stripe docs * fix condition * fix condition * fix module defintion * fix checkout * disable UI action * change oas preview action * flatten provider module options * fix lint errors * add module link docs * pr comments fixes * fix vale error * change node engine version * links -> linkable * add note about database name * small fixes * link fixes * fix response code in api reference * added migrations step
This commit is contained in:
@@ -42,12 +42,11 @@ export default class HelloModuleService {
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Loader
|
||||
|
||||
A loader function in a module accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources.
|
||||
A loader function accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -64,5 +63,4 @@ export default function helloWorldLoader({
|
||||
|
||||
logger.info("[helloWorldLoader]: Hello, World!")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -4,12 +4,12 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you'll learn about how modules are isolated, and what that means for your custom development.
|
||||
In this chapter, you'll learn how modules are isolated, and what that means for your custom development.
|
||||
|
||||
<Note title="Summary">
|
||||
|
||||
- Modules can't access resources, such as services, from other modules.
|
||||
- You can use Medusa's tools, explained in the next chapters, to extend modules or implement features across modules.
|
||||
- You can use Medusa's tools, as explained in the next chapters, to extend a modules' features or implement features across modules.
|
||||
|
||||
</Note>
|
||||
|
||||
@@ -17,13 +17,13 @@ In this chapter, you'll learn about how modules are isolated, and what that mean
|
||||
|
||||
A module is unaware of any resources other than its own, such as services or data models. This means it can't access these resources if they're implemented in another module.
|
||||
|
||||
For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to another module's data model.
|
||||
For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to the Product Module's data models.
|
||||
|
||||
---
|
||||
|
||||
## Customize and Implement Features Across Modules
|
||||
## How to Implement Custom Features Across Modules?
|
||||
|
||||
In your Medusa application, you want to implement features that span across modules, or you want to extend existing modules to add new features.
|
||||
In your Medusa application, you want to implement features that span across modules, or you want to extend an existing module's features and customize them for your own use case.
|
||||
|
||||
For example, you want to extend the Product Module to add new properties to the `Product` data model.
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Link Modules`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn what a link module is and how to use the remote link in your customizations.
|
||||
|
||||
## What is a Link Module?
|
||||
|
||||
A link module is a module whose only purpose is to define a relationship between two modules’ data models. The relationship is represented as a pivot or link table in the database, pointing at the primary keys of each data model.
|
||||
|
||||
For example, Medusa has a link module that defines a relationship between the Product and Pricing modules. It links the `ProductVariant` and `PriceSet` data models.
|
||||
|
||||

|
||||
|
||||
Link modules create the relationship between modules while maintaining module isolation. The Medusa application only creates the link tables when both modules are available.
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Link modules are currently only available for Medusa’s commerce modules.
|
||||
|
||||
</Note>
|
||||
@@ -0,0 +1,128 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Module Link`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn what a module link is.
|
||||
|
||||
<Note type="soon" title="In Development">
|
||||
|
||||
Module links are in active development.
|
||||
|
||||
</Note>
|
||||
|
||||
## What is a Module Link?
|
||||
|
||||
A module link forms an association between two data models of different modules, while maintaining module isolation.
|
||||
|
||||
You can then retrieve data across the linked modules, and manage their linked records.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisite: isQueryable Configuration
|
||||
|
||||
Before you define a module link, you must enable the `isQueryable` configuration of the module.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
module.exports = defineConfig({
|
||||
// ...
|
||||
modules: {
|
||||
helloModuleService: {
|
||||
resolve: "./modules/hello",
|
||||
definition: {
|
||||
isQueryable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How to Define a Module Link?
|
||||
|
||||
### 1. Create Link File
|
||||
|
||||
Links are defined in a TypeScript or JavaScript file under the `src/links` directory. The file defines the link using the `defineLink` function imported from `@medusajs/utils` and exports it.
|
||||
|
||||
For example:
|
||||
|
||||
export const highlights = [
|
||||
["6", "linkable", "Special `linkable` property that holds the linkable data models of `HelloModule`."],
|
||||
["7", "linkable", "Special `linkable` property that holds the linkable data models of `ProductModule`."],
|
||||
]
|
||||
|
||||
```ts title="src/links/hello-product.ts" highlights={highlights}
|
||||
import HelloModule from "../modules/hello"
|
||||
import ProductModule from "@medusajs/product"
|
||||
import { defineLink } from "@medusajs/utils"
|
||||
|
||||
export default defineLink(
|
||||
HelloModule.linkable.myCustom,
|
||||
ProductModule.linkable.product
|
||||
)
|
||||
```
|
||||
|
||||
The `defineLink` function accepts as parameters the link configurations of each module's data model. A module has a special `linkable` property that holds these configurations for its data models.
|
||||
|
||||
In this example, you define a module link between the `hello` module's `MyCustom` data model and the Product Module's `Product` data model.
|
||||
|
||||
### 2. Run Migrations
|
||||
|
||||
Medusa stores links as pivot tables in the database, so you must run migrations after defining a link:
|
||||
|
||||
```bash
|
||||
npx medusa migrations run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Define a List Link
|
||||
|
||||
By default, the defined link establishes a one-to-one relation: a record of a data model is linked to one record of the other data model.
|
||||
|
||||
To specify that a data model can have multiple of its records linked to the other data model's record, use the `isList` option.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import HelloModule from "../modules/hello"
|
||||
import ProductModule from "@medusajs/product"
|
||||
import { defineLink } from "@medusajs/utils"
|
||||
|
||||
export default defineLink(
|
||||
{
|
||||
model: HelloModule.linkable.myCustom,
|
||||
isList: true
|
||||
},
|
||||
ProductModule.linkable.product
|
||||
)
|
||||
```
|
||||
|
||||
In this case, you pass an object of configuration as a parameter rather than the linked model. The object accepts the following properties:
|
||||
|
||||
- `model`: The data model to link.
|
||||
- `isList`: Whether multiple records can be linked to one record of the other data model.
|
||||
|
||||
In this example, a record of `product` can be linked to more than one record of `myCustom`.
|
||||
|
||||
---
|
||||
|
||||
## Extend Data Models with Module Links
|
||||
|
||||
Module links are most useful when you want to add properties to a data model of another module.
|
||||
|
||||
For example, to add custom properties to the `Product` data model of the Product Module, you:
|
||||
|
||||
1. Create a module.
|
||||
2. Create in the module a data model that holds the custom properties you want to add to the `Product` data model.
|
||||
2. Define a module link that links your module to the Product Module.
|
||||
|
||||
Then, in the next chapters, you'll learn how to:
|
||||
|
||||
- Link each product to a record of your data model.
|
||||
- Retrieve your data model's properties when you retrieve products.
|
||||
|
||||
@@ -80,7 +80,7 @@ The object that a module’s loaders receive as a parameter has an `options` pro
|
||||
|
||||
For example:
|
||||
|
||||
```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["16"]]}
|
||||
```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["12", "ModuleOptions", "The type of expected module options."], ["16"]]}
|
||||
import {
|
||||
LoaderOptions,
|
||||
} from "@medusajs/modules-sdk"
|
||||
|
||||
@@ -6,9 +6,15 @@ export const metadata = {
|
||||
|
||||
In this chapter, you’ll learn what the remote link is and how to use it to manage links.
|
||||
|
||||
<Note type="soon" title="In Development">
|
||||
|
||||
Remote Links are in active development.
|
||||
|
||||
</Note>
|
||||
|
||||
## What is the Remote Link?
|
||||
|
||||
The remote link is a class with utility methods to manage links defined by the link module. It’s registered in the Medusa container under the `remoteLink` registration name.
|
||||
The remote link is a class with utility methods to manage links between data models. It’s registered in the Medusa container under the `remoteLink` registration name.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -38,7 +44,9 @@ export async function POST(
|
||||
|
||||
You can use its methods to manage links, such as create or delete links.
|
||||
|
||||
### Create Link
|
||||
---
|
||||
|
||||
## Create Link
|
||||
|
||||
To create a link between records of two data models, use the `create` method of the remote link.
|
||||
|
||||
@@ -51,23 +59,25 @@ import { Modules } from "@medusajs/utils"
|
||||
|
||||
await remoteLink.create({
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[0].id,
|
||||
product_id: "prod_123",
|
||||
},
|
||||
[Modules.PRICING]: {
|
||||
price_set_id: price.id,
|
||||
"hello": {
|
||||
my_custom_id: "mc_123",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
The `create` method accepts as a parameter an object. The object’s keys are the names of the linked modules.
|
||||
|
||||
The value of each module’s property is an object. It defines the values of the linked fields.
|
||||
The value of each module’s property is an object, whose keys are of the format `{data_model_snake_name}_id`, and values are the IDs of the linked record.
|
||||
|
||||
So, in the example above, you specify for the Product Module the value of the `variant_id`, and for the Pricing Module the value of `price_set_id`. These are the fields linked between the models of the two modules.
|
||||
So, in the example above, you link a record of the `MyCustom` data model in a `hello` module to a `Product` record in the Product Module.
|
||||
|
||||
### Dismiss Link
|
||||
---
|
||||
|
||||
To remove a link between records of two data models, use the `dismiss` method of the remote link. This doesn’t remove the records, only the relation between them.
|
||||
## Dismiss Link
|
||||
|
||||
To remove a link between records of two data models, use the `dismiss` method of the remote link.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -78,19 +88,21 @@ import { Modules } from "@medusajs/utils"
|
||||
|
||||
await remoteLink.dismiss({
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: product.variants[0].id,
|
||||
product_id: "prod_123",
|
||||
},
|
||||
[Modules.PRICING]: {
|
||||
price_set_id: price.id,
|
||||
"hello": {
|
||||
my_custom_id: "mc_123",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
The `dismiss` method accepts the same parameter type as the [create method](#create-link).
|
||||
|
||||
### Cascade Delete Linked Records
|
||||
---
|
||||
|
||||
If a record, such as a variant, is deleted, use the `delete` method of the remote link to delete all associated links with cascade delete enabled.
|
||||
## Cascade Delete Linked Records
|
||||
|
||||
If a record is deleted, use the `delete` method of the remote link to delete all linked records.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -103,16 +115,18 @@ await productModuleService.deleteVariants([variant.id])
|
||||
|
||||
await remoteLink.delete({
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: variant.id,
|
||||
product_id: "prod_123",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
This deletes all records linked to the deleted variant with cascade delete enabled in their relationship.
|
||||
This deletes all records linked to the deleted product.
|
||||
|
||||
### Restore Linked Records
|
||||
---
|
||||
|
||||
If a record, such as a variant, that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all associated links that were cascade deleted.
|
||||
## Restore Linked Records
|
||||
|
||||
If a record that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all linked records.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -121,77 +135,11 @@ import { Modules } from "@medusajs/utils"
|
||||
|
||||
// ...
|
||||
|
||||
await productModuleService.restoreVariants([variant.id])
|
||||
await productModuleService.restoreProducts(["prod_123"])
|
||||
|
||||
await remoteLink.restore({
|
||||
[Modules.PRODUCT]: {
|
||||
variant_id: variant.id,
|
||||
product_id: "prod_123",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Link Module's Service
|
||||
|
||||
The remote link has a `getLinkModule` method to retrieve the service of the link module. This service has `list` and `retrieve` methods to retrieve the linked items.
|
||||
|
||||
For example, to retrieve the link module of the Product and Pricing modules:
|
||||
|
||||
export const linkModuleServiceHighlights = [
|
||||
["6", "Modules.PRODUCT", "The name of the first module in the link module's definition."],
|
||||
["7", '"variant_id"', "The foreign key that links to the record in the first module."],
|
||||
["8", "Modules.PRICING", "The name of the second module in the link module's definition."],
|
||||
["9", '"price_set_id"', "The foreign key that links to the record in the second module."],
|
||||
["12", "", "The link module's service is undefined if either of the modules isn't installed or there's no link module with the specified definition."]
|
||||
]
|
||||
|
||||
```ts highlights={linkModuleServiceHighlights}
|
||||
import { Modules } from "@medusajs/utils"
|
||||
|
||||
// ...
|
||||
|
||||
const linkModuleService = remoteLink.getLinkModule(
|
||||
Modules.PRODUCT,
|
||||
"variant_id",
|
||||
Modules.PRICING,
|
||||
"price_set_id"
|
||||
)
|
||||
|
||||
if (!linkModuleService) {
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
The `getLinkModule` method accepts four parameter:
|
||||
|
||||
1. A string indicating the name of the first module in the link module's definition.
|
||||
2. A string indicating the foreign key that links to the record in the first module.
|
||||
3. A string indicating the name of the second module in the link module's definition.
|
||||
4. A string indicating the foreign key that links to the record in the second module.
|
||||
|
||||
Notice that the returned link module service might be undefined if either of the modules isn't installed, or if there's no link module with the specified definition.
|
||||
|
||||
### List Linked Items
|
||||
|
||||
The link module's service has a `list` method that retrieves a list of linked records. It also accepts filters to retrieve specific linked items.
|
||||
|
||||
For example, to retrieve the price sets linked to a variant:
|
||||
|
||||
```ts
|
||||
import { Modules } from "@medusajs/utils"
|
||||
|
||||
// ...
|
||||
|
||||
const linkModuleService = remoteLink.getLinkModule(
|
||||
Modules.PRODUCT,
|
||||
"variant_id",
|
||||
Modules.PRICING,
|
||||
"price_set_id"
|
||||
)
|
||||
|
||||
const items = await linkModuleService.list(
|
||||
{ variant_id: [variant.id] },
|
||||
{ select: ["variant_id", "price_set_id"] }
|
||||
)
|
||||
```
|
||||
|
||||
@@ -14,27 +14,11 @@ The remote query fetches data across modules. It’s a function registered in th
|
||||
|
||||
In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusa’s commerce modules.
|
||||
|
||||
---
|
||||
<Note type="check">
|
||||
|
||||
## isQueryable Configuration
|
||||
- [Enable the isQueryable configuration of the module](../module-links/page.mdx#prerequisite-isqueryable-configuration)
|
||||
|
||||
Before you use remote query on your module, you must enable the `isQueryable` configuration of the module.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
module.exports = defineConfig({
|
||||
// ...
|
||||
modules: {
|
||||
helloModuleService: {
|
||||
resolve: "./modules/hello",
|
||||
definition: {
|
||||
isQueryable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
@@ -93,6 +77,48 @@ You then pass the query to the `remoteQuery` function to retrieve the results.
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Linked Records
|
||||
|
||||
Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"product.*"
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
`.*` 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`.
|
||||
|
||||
</Note>
|
||||
|
||||
### Retrieve List Link Records
|
||||
|
||||
If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts highlights={[["6"]]}
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "my_custom",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"products.*"
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Apply Filters
|
||||
|
||||
```ts highlights={[["6"], ["7"], ["8"], ["9"]]}
|
||||
@@ -259,6 +285,8 @@ The remote query function alternatively accepts a string with GraphQL syntax as
|
||||
}
|
||||
`
|
||||
|
||||
const result = await remoteQuery(query)
|
||||
|
||||
res.json({
|
||||
my_customs: result,
|
||||
})
|
||||
|
||||
@@ -12,9 +12,9 @@ In this chapter, you’ll learn about what the service factory is and how to use
|
||||
|
||||
Medusa provides a service factory that your module’s main service can extend.
|
||||
|
||||
The service factory generates data management methods for your data models, so you don't have to implement them manually.
|
||||
The service factory generates data management methods for your data models, so you don't have to implement these methods manually.
|
||||
|
||||
<Note title="Use the service factory when" type="success">
|
||||
<Note title="Extend the service factory when" type="success">
|
||||
|
||||
- Your service provides data-management functionalities of your data models.
|
||||
|
||||
@@ -50,7 +50,7 @@ export default HelloModuleService
|
||||
|
||||
The `MedusaService` function accepts one parameter, which is an object of data models to generate data-management methods for.
|
||||
|
||||
In the example above, the `HelloModuleService` now has methods to manage the `MyCustom` data model, such as `createMyCustoms`.
|
||||
In the example above, since the `HelloModuleService` extends `MedusaService`, it has methods to manage the `MyCustom` data model, such as `createMyCustoms`.
|
||||
|
||||
### Generated Methods
|
||||
|
||||
|
||||
Reference in New Issue
Block a user