docs: add documentation for Locking Module (#11824)
* add locking docs * fix main navbar * added implementation example links * generate refs * update architecture * fix vale error
This commit is contained in:
@@ -25,6 +25,7 @@ import { TypeList } from "docs-ui"
|
||||
- [inventory-next](modules/inventory_next/page.mdx)
|
||||
- [inventory-next-models](modules/inventory_next_models/page.mdx)
|
||||
- [js-sdk](modules/js_sdk/page.mdx)
|
||||
- [locking](modules/locking/page.mdx)
|
||||
- [medusa](modules/medusa/page.mdx)
|
||||
- [medusa-config](modules/medusa_config/page.mdx)
|
||||
- [modules-sdk](modules/modules_sdk/page.mdx)
|
||||
|
||||
+18
-10
@@ -9,9 +9,17 @@ sidebar_label: Create Auth Provider
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create an Auth Provider Module
|
||||
# How to Create an Auth Module Provider
|
||||
|
||||
In this document, you’ll learn how to create an auth provider module and the methods you must implement in its main service.
|
||||
In this document, you’ll learn how to create an Auth Module Provider and the methods you must implement in its main service.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Example
|
||||
|
||||
As you implement your Auth Module Provider, it can be useful to refer to an existing provider and how it's implemeted.
|
||||
|
||||
If you need to refer to an existing implementation as an example, check the [Google Auth Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/auth-google).
|
||||
|
||||
---
|
||||
|
||||
@@ -31,9 +39,9 @@ The rest of this guide always uses the `src/modules/my-auth` directory as an exa
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Auth Provider Service
|
||||
## 2. Create the Auth Module Provider's Service
|
||||
|
||||
Create the file `src/modules/my-auth/service.ts` that holds the module's main service. It must extend the `AbstractAuthModuleProvider` class imported from `@medusajs/framework/utils`:
|
||||
Create the file `src/modules/my-auth/service.ts` that holds the module provider's main service. It must extend the `AbstractAuthModuleProvider` class imported from `@medusajs/framework/utils`:
|
||||
|
||||
```ts title="src/modules/my-auth/service.ts"
|
||||
import { AbstractAuthModuleProvider } from "@medusajs/framework/utils"
|
||||
@@ -453,7 +461,7 @@ class MyAuthProviderService extends AbstractAuthModuleProvider {
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-auth/index.ts` with the following content:
|
||||
|
||||
@@ -469,11 +477,11 @@ export default ModuleProvider(Modules.AUTH, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyAuthProviderService` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyAuthProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Auth Module Provider, add it to the `providers` array of the Auth Module in `medusa-config.ts`:
|
||||
|
||||
@@ -513,9 +521,9 @@ module.exports = defineConfig({
|
||||
|
||||
## 5. Test it Out
|
||||
|
||||
To test out your authentication provider, use any of the [Authentication Routes](https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route), using your provider's ID as a path parameter.
|
||||
To test out your Authentication Module Provider, use any of the [Authentication Routes](https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route), using your provider's ID as a path parameter.
|
||||
|
||||
For example, to get a registration token for an admin user, send a `POST` request to `/auth/user/my-auth/register` replacing `my-auth` with your authentication provider's ID:
|
||||
For example, to get a registration token for an admin user, send a `POST` request to `/auth/user/my-auth/register` replacing `my-auth` with your Authentication Module Provider's ID:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9000/auth/user/my-auth/register
|
||||
@@ -525,6 +533,6 @@ curl -X POST http://localhost:9000/auth/user/my-auth/register
|
||||
}'
|
||||
```
|
||||
|
||||
Change the request body to pass the data required for your authentication provider to register the user.
|
||||
Change the request body to pass the data required for your Authentication Module Provider to register the user.
|
||||
|
||||
If registration is successful, the response will have a `token` property.
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createCartsStep({
|
||||
"currency_code": "jpy"
|
||||
"currency_code": "php"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = retrieveCartStep({
|
||||
"id": "id_NC6OB61K97Y"
|
||||
"id": "id_8UxqXFwvGKp1K"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateCartPromotionsStep({
|
||||
"id": "id_DffiOIkGMKk1ORZHgv"
|
||||
"id": "id_QjunYRvNPLqC"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+4
-4
@@ -34,7 +34,7 @@ export async function POST(
|
||||
.run({
|
||||
input: {
|
||||
"id": [
|
||||
"id_dCWncxGdqNJe1Xa8"
|
||||
"id_bemxq4oJiSTZn"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -61,7 +61,7 @@ export default async function handleOrderPlaced({
|
||||
.run({
|
||||
input: {
|
||||
"id": [
|
||||
"id_dCWncxGdqNJe1Xa8"
|
||||
"id_bemxq4oJiSTZn"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -88,7 +88,7 @@ export default async function myCustomJob(
|
||||
.run({
|
||||
input: {
|
||||
"id": [
|
||||
"id_dCWncxGdqNJe1Xa8"
|
||||
"id_bemxq4oJiSTZn"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -116,7 +116,7 @@ const myWorkflow = createWorkflow(
|
||||
.runAsStep({
|
||||
input: {
|
||||
"id": [
|
||||
"id_dCWncxGdqNJe1Xa8"
|
||||
"id_bemxq4oJiSTZn"
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createCustomerGroupsStep({
|
||||
"name": "Oswald"
|
||||
"name": "Reuben"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createFulfillmentSets({
|
||||
"name": "Otha",
|
||||
"name": "Princess",
|
||||
"type": "{value}"
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createServiceZonesStep({
|
||||
"name": "Braulio",
|
||||
"name": "Chesley",
|
||||
"fulfillment_set_id": "{value}"
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ const myWorkflow = createWorkflow(
|
||||
const data = createShippingOptionRulesStep({
|
||||
"data": [{
|
||||
"attribute": "{value}",
|
||||
"operator": "eq",
|
||||
"operator": "lte",
|
||||
"value": "{value}",
|
||||
"shipping_option_id": "{value}"
|
||||
}]
|
||||
|
||||
+3
-3
@@ -22,10 +22,10 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createShippingOptionsPriceSetsStep({
|
||||
"id": "id_W67Buk6sFY",
|
||||
"id": "id_HIsRdDyns3y1mST4",
|
||||
"prices": [{
|
||||
"currency_code": "bsd",
|
||||
"amount": 50
|
||||
"currency_code": "mur",
|
||||
"amount": 49
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createShippingProfilesStep({
|
||||
"name": "Terry",
|
||||
"name": "Roslyn",
|
||||
"type": "{value}"
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteShippingOptionRulesStep({
|
||||
"ids": [
|
||||
"id_nM64LyjlsAZ"
|
||||
"id_w0STpU4jGRJcMAB"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateInventoryItemsStep({
|
||||
"id": "id_mQEVzVbUaYJLgjQJY"
|
||||
"id": "id_vM0T4AzOH45pTg"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = validateInventoryDeleteStep({
|
||||
"inventory_items": [{
|
||||
"id": "id_rGGlYBgTmX",
|
||||
"reserved_quantity": 32
|
||||
"id": "id_rwtTvcCy9pEA1AzENO8",
|
||||
"reserved_quantity": 13
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = addOrderTransactionStep({
|
||||
"order_id": "order_123",
|
||||
"amount": 48,
|
||||
"currency_code": "idr"
|
||||
"amount": 11,
|
||||
"currency_code": "szl"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = cancelOrderChangeStep({
|
||||
"id": "id_DaKY1rN96N4Dye1i4UZ"
|
||||
"id": "id_ZFBssHt8s8B1wyV"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = createOrderClaimsStep([{
|
||||
"order_id": "order_123",
|
||||
"type": "refund"
|
||||
"type": "replace"
|
||||
}])
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = declineOrderChangeStep({
|
||||
"id": "id_Ou7TQ3XETnVPfiyeBxn"
|
||||
"id": "id_2wLDxjDAU1BmB7Z"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteClaimsStep({
|
||||
"ids": [
|
||||
"id_5kuTB79Xd8e14Y9BW6MH"
|
||||
"id_8ubWMJmV8tFQACwSBRwB"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteExchangesStep({
|
||||
"ids": [
|
||||
"id_ocY7t3llf5aL1"
|
||||
"id_IS3vD87dhABzz"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteOrderChangeActionsStep({
|
||||
"ids": [
|
||||
"id_DoNSMAC7x7yoiK67f3m"
|
||||
"id_VTfP6NhpWdAnGb9b"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteOrderChangesStep({
|
||||
"ids": [
|
||||
"id_s5kEPzEoBHwZamIZf"
|
||||
"id_aL7s50hQv4X"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteOrderLineItems({
|
||||
"ids": [
|
||||
"id_qCoJvWGyVfQq5TC4LX"
|
||||
"id_WQTEJb19KEWjtGsjr8MQ"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteOrderShippingMethods({
|
||||
"ids": [
|
||||
"id_R9Ui7kOsEp"
|
||||
"id_kB1A5qCI99"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deleteReturnsStep({
|
||||
"ids": [
|
||||
"id_BTC6cHX3wCg6Ff"
|
||||
"id_G4woLBjcA55As"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateOrderChangeActionsStep({
|
||||
"id": "id_YOUTShFPTOVb9hr"
|
||||
"id": "id_vYJUMkfGqAUG"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateOrderChangesStep({
|
||||
"id": "id_2FI3REzv0cccw9"
|
||||
"id": "id_39fPc4du4SYpubPg2"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateOrderShippingMethodsStep({
|
||||
"id": "id_xwOv7C5wTuE"
|
||||
"id": "id_YxuvxvhYAEfz"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateReturnsStep({
|
||||
"id": "id_V3qdW375AIzZCxbK8FRK"
|
||||
"id": "id_y6VNwEVxTmUDauPsD2L"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ export async function POST(
|
||||
const { result } = await cancelOrderChangeWorkflow(req.scope)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_TifTyReowGmg5yEQQLT"
|
||||
"id": "id_7cSs3D0glvQGX5o89r"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ export default async function handleOrderPlaced({
|
||||
const { result } = await cancelOrderChangeWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_TifTyReowGmg5yEQQLT"
|
||||
"id": "id_7cSs3D0glvQGX5o89r"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -89,7 +89,7 @@ export default async function myCustomJob(
|
||||
const { result } = await cancelOrderChangeWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_TifTyReowGmg5yEQQLT"
|
||||
"id": "id_7cSs3D0glvQGX5o89r"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ const myWorkflow = createWorkflow(
|
||||
const result = cancelOrderChangeWorkflow
|
||||
.runAsStep({
|
||||
input: {
|
||||
"id": "id_TifTyReowGmg5yEQQLT"
|
||||
"id": "id_7cSs3D0glvQGX5o89r"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ export async function POST(
|
||||
const { result } = await createOrderChangeActionsWorkflow(req.scope)
|
||||
.run({
|
||||
input: [{
|
||||
"action": "UPDATE_ORDER_PROPERTIES"
|
||||
"action": "DELIVER_ITEM"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ export default async function handleOrderPlaced({
|
||||
const { result } = await createOrderChangeActionsWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"action": "UPDATE_ORDER_PROPERTIES"
|
||||
"action": "DELIVER_ITEM"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -89,7 +89,7 @@ export default async function myCustomJob(
|
||||
const { result } = await createOrderChangeActionsWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"action": "UPDATE_ORDER_PROPERTIES"
|
||||
"action": "DELIVER_ITEM"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ const myWorkflow = createWorkflow(
|
||||
const result = createOrderChangeActionsWorkflow
|
||||
.runAsStep({
|
||||
input: [{
|
||||
"action": "UPDATE_ORDER_PROPERTIES"
|
||||
"action": "DELIVER_ITEM"
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ export async function POST(
|
||||
const { result } = await declineOrderChangeWorkflow(req.scope)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_feqdUcXMDHpl5BhrF1"
|
||||
"id": "id_wjqnrdNeurl7p"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ export default async function handleOrderPlaced({
|
||||
const { result } = await declineOrderChangeWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_feqdUcXMDHpl5BhrF1"
|
||||
"id": "id_wjqnrdNeurl7p"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -89,7 +89,7 @@ export default async function myCustomJob(
|
||||
const { result } = await declineOrderChangeWorkflow(container)
|
||||
.run({
|
||||
input: {
|
||||
"id": "id_feqdUcXMDHpl5BhrF1"
|
||||
"id": "id_wjqnrdNeurl7p"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ const myWorkflow = createWorkflow(
|
||||
const result = declineOrderChangeWorkflow
|
||||
.runAsStep({
|
||||
input: {
|
||||
"id": "id_feqdUcXMDHpl5BhrF1"
|
||||
"id": "id_wjqnrdNeurl7p"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -40,7 +40,7 @@ export async function POST(
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_ejESZlHpfen57ANk8MzQ"
|
||||
"id_LZttQo8M2Bg"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -67,7 +67,7 @@ export default async function handleOrderPlaced({
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_ejESZlHpfen57ANk8MzQ"
|
||||
"id_LZttQo8M2Bg"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -94,7 +94,7 @@ export default async function myCustomJob(
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_ejESZlHpfen57ANk8MzQ"
|
||||
"id_LZttQo8M2Bg"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -122,7 +122,7 @@ const myWorkflow = createWorkflow(
|
||||
.runAsStep({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_ejESZlHpfen57ANk8MzQ"
|
||||
"id_LZttQo8M2Bg"
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
+4
-4
@@ -40,7 +40,7 @@ export async function POST(
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_cVndBSTOaDeZrGfM6"
|
||||
"id_VmvGq4qPHDULT"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -67,7 +67,7 @@ export default async function handleOrderPlaced({
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_cVndBSTOaDeZrGfM6"
|
||||
"id_VmvGq4qPHDULT"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -94,7 +94,7 @@ export default async function myCustomJob(
|
||||
.run({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_cVndBSTOaDeZrGfM6"
|
||||
"id_VmvGq4qPHDULT"
|
||||
]
|
||||
}
|
||||
})
|
||||
@@ -122,7 +122,7 @@ const myWorkflow = createWorkflow(
|
||||
.runAsStep({
|
||||
input: {
|
||||
"ids": [
|
||||
"id_cVndBSTOaDeZrGfM6"
|
||||
"id_VmvGq4qPHDULT"
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
+6
-6
@@ -23,15 +23,15 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = throwUnlessStatusIsNotPaid({
|
||||
"paymentCollection": {
|
||||
"id": "id_eAJuwhOu8bg3",
|
||||
"currency_code": "bbd",
|
||||
"id": "id_vGqsmproyL2X3fOeWS",
|
||||
"currency_code": "bhd",
|
||||
"amount": {
|
||||
"numeric": 20
|
||||
"numeric": 43
|
||||
},
|
||||
"status": "completed",
|
||||
"status": "not_paid",
|
||||
"payment_providers": [{
|
||||
"id": "id_z5AQyPaFFn0",
|
||||
"is_enabled": true
|
||||
"id": "id_LMlRiwKBdHvYo",
|
||||
"is_enabled": false
|
||||
}]
|
||||
}
|
||||
})
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ export async function POST(
|
||||
const { result } = await updateOrderChangeActionsWorkflow(req.scope)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_Iy3nRPjiHKo9sWnOrk"
|
||||
"id": "id_NhKl53pnyDSMMKE2I"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ export default async function handleOrderPlaced({
|
||||
const { result } = await updateOrderChangeActionsWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_Iy3nRPjiHKo9sWnOrk"
|
||||
"id": "id_NhKl53pnyDSMMKE2I"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -89,7 +89,7 @@ export default async function myCustomJob(
|
||||
const { result } = await updateOrderChangeActionsWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_Iy3nRPjiHKo9sWnOrk"
|
||||
"id": "id_NhKl53pnyDSMMKE2I"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ const myWorkflow = createWorkflow(
|
||||
const result = updateOrderChangeActionsWorkflow
|
||||
.runAsStep({
|
||||
input: [{
|
||||
"id": "id_Iy3nRPjiHKo9sWnOrk"
|
||||
"id": "id_NhKl53pnyDSMMKE2I"
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -39,7 +39,7 @@ export async function POST(
|
||||
const { result } = await updateOrderChangesWorkflow(req.scope)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_HCKR2lBPbpaAtaU"
|
||||
"id": "id_5n831DKhYtSIYgCvx"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ export default async function handleOrderPlaced({
|
||||
const { result } = await updateOrderChangesWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_HCKR2lBPbpaAtaU"
|
||||
"id": "id_5n831DKhYtSIYgCvx"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -89,7 +89,7 @@ export default async function myCustomJob(
|
||||
const { result } = await updateOrderChangesWorkflow(container)
|
||||
.run({
|
||||
input: [{
|
||||
"id": "id_HCKR2lBPbpaAtaU"
|
||||
"id": "id_5n831DKhYtSIYgCvx"
|
||||
}]
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ const myWorkflow = createWorkflow(
|
||||
const result = updateOrderChangesWorkflow
|
||||
.runAsStep({
|
||||
input: [{
|
||||
"id": "id_HCKR2lBPbpaAtaU"
|
||||
"id": "id_5n831DKhYtSIYgCvx"
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ const myWorkflow = createWorkflow(
|
||||
const data = createPaymentSessionStep({
|
||||
"payment_collection_id": "{value}",
|
||||
"provider_id": "{value}",
|
||||
"amount": 33,
|
||||
"currency_code": "bnd"
|
||||
"amount": 27,
|
||||
"currency_code": "rwf"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = deletePaymentSessionsStep({
|
||||
"ids": [
|
||||
"id_CCBxiUKjH8BnhzJDbGgD"
|
||||
"id_q21Y5traw5UZlU0"
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = updateRefundReasonsStep({
|
||||
"id": "id_88bbRFUmjXhbI8wsvZn7"
|
||||
"id": "id_ydhQzcRGB4f"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = validatePriceListsStep({
|
||||
"id": "id_eT8yS6k97cLV0Xq42"
|
||||
"id": "id_r2rvymnVIzUW"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createCollectionsStep([{
|
||||
"title": "amplexus"
|
||||
"title": "vestrum"
|
||||
}])
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ const myWorkflow = createWorkflow(
|
||||
() => {
|
||||
const data = updatePromotionsValidationStep({
|
||||
"promotionsData": [{
|
||||
"id": "id_8RHhRkuHKZdQcFyvzazV",
|
||||
"id": "id_e4yTROodl3VoMJIda0",
|
||||
"status": "draft"
|
||||
}]
|
||||
})
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ const myWorkflow = createWorkflow(
|
||||
"my-workflow",
|
||||
() => {
|
||||
const data = createStockLocations({
|
||||
"name": "Eula"
|
||||
"name": "Maybell"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
+16
-8
@@ -4,9 +4,17 @@ slug: /references/file-provider-module
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a File Provider Module
|
||||
# How to Create a File Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a file provider module and the methods you must implement in its main service.
|
||||
In this document, you’ll learn how to create a File Module Provider and the methods you must implement in its main service.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Example
|
||||
|
||||
As you implement your File Module Provider, it can be useful to refer to an existing provider and how it's implemeted.
|
||||
|
||||
If you need to refer to an existing implementation as an example, check the [S3 File Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/file-s3).
|
||||
|
||||
---
|
||||
|
||||
@@ -26,9 +34,9 @@ The rest of this guide always uses the `src/modules/my-file` directory as an exa
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the File Provider Service
|
||||
## 2. Create the File Module Provider's Service
|
||||
|
||||
Create the file `src/modules/my-file/service.ts` that holds the implementation of the module's main service. It must extend the `AbstractFileProviderService` class imported from `@medusajs/framework/utils`:
|
||||
Create the file `src/modules/my-file/service.ts` that holds the implementation of the module provider's main service. It must extend the `AbstractFileProviderService` class imported from `@medusajs/framework/utils`:
|
||||
|
||||
```ts title="src/modules/my-file/service.ts"
|
||||
import { AbstractFileProviderService } from "@medusajs/framework/utils"
|
||||
@@ -224,7 +232,7 @@ class MyFileProviderService extends AbstractFileProviderService {
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-file/index.ts` with the following content:
|
||||
|
||||
@@ -240,11 +248,11 @@ export default ModuleProvider(Modules.FILE, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyFileProviderService` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyFileProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your File Module Provider, add it to the `providers` array of the File Module in `medusa-config.ts`:
|
||||
|
||||
@@ -286,4 +294,4 @@ module.exports = defineConfig({
|
||||
|
||||
## 5. Test it Out
|
||||
|
||||
To test out your file provider, use the Medusa Admin or the [Upload API route](https://docs.medusajs.com/v2/api/admin#uploads_postuploads) to upload a file.
|
||||
To test out your File Module Provider, use the Medusa Admin or the [Upload API route](https://docs.medusajs.com/v2/api/admin#uploads_postuploads) to upload a file.
|
||||
|
||||
+12
-12
@@ -9,17 +9,17 @@ sidebar_label: Create Fulfillment Provider
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a Fulfillment Provider Module
|
||||
# How to Create a Fulfillment Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a fulfillment provider module and the methods you must implement in its main service.
|
||||
In this document, you’ll learn how to create a Fulfillment Module Provider and the methods you must implement in its main service.
|
||||
|
||||
---
|
||||
|
||||
## Understanding Fulfillment Provider Implementation
|
||||
## Understanding Fulfillment Module Provider Implementation
|
||||
|
||||
The Fulfillment Module Provider handles processing fulfillments and shipments with a third-party provirder. However, it's not responsible for managing fulfillment concepts within Medusa, such as creating a fulfillment or its shipments. The Fulfillment Module uses your fulfillment provider within core operations.
|
||||
The Fulfillment Module Provider handles processing fulfillments and shipments with a third-party provirder. However, it's not responsible for managing fulfillment concepts within Medusa, such as creating a fulfillment or its shipments. The Fulfillment Module uses your Fulfillment Module Provider within core operations.
|
||||
|
||||
For example, when the merchant creates a fulfillment for an order, the Fulfillment Module uses your fulfillment provider to create the fulfillment in the third-party system, then creates the fulfillment in Medusa. So, you only have to implement the third-party fulfillment processing logic in your fulfillment provider.
|
||||
For example, when the merchant creates a fulfillment for an order, the Fulfillment Module uses your Fulfillment Module Provider to create the fulfillment in the third-party system, then creates the fulfillment in Medusa. So, you only have to implement the third-party fulfillment processing logic in your Fulfillment Module Provider.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,9 +39,9 @@ The rest of this guide always uses the `src/modules/my-fulfillment` directory as
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Fulfillment Provider Service
|
||||
## 2. Create the Fulfillment Module Provider Service
|
||||
|
||||
Create the file `src/modules/my-fulfillment/service.ts` that holds the module's main service. It must extend the `AbstractFulfillmentProviderService` class imported from `@medusajs/framework/utils`:
|
||||
Create the file `src/modules/my-fulfillment/service.ts` that holds the module provider's main service. It must extend the `AbstractFulfillmentProviderService` class imported from `@medusajs/framework/utils`:
|
||||
|
||||
```ts title="src/modules/my-fulfillment/service.ts"
|
||||
import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
|
||||
@@ -519,7 +519,7 @@ class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-fulfillment/index.ts` with the following content:
|
||||
|
||||
@@ -535,11 +535,11 @@ export default ModuleProvider(Modules.FULFILLMENT, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyFulfillmentProviderService` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyFulfillmentProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Fulfillment Module Provider, add it to the `providers` array of the Fulfillment Module in `medusa-config.ts`:
|
||||
|
||||
@@ -575,9 +575,9 @@ module.exports = defineConfig({
|
||||
|
||||
## 5. Test it Out
|
||||
|
||||
Before you use your fulfillment provider, in the Medusa Admin:
|
||||
Before you use your Fulfillment Module Provider, in the Medusa Admin:
|
||||
|
||||
1. Add the fulfillment provider to a location.
|
||||
1. Add the Fulfillment Module Provider to a location.
|
||||
2. Add in the location a delivery shipping option that uses the provider.
|
||||
|
||||
Then, place an order, choosing the shipping option you created during checkout, and create a fulfillment in the Medusa Admin. The fulfillment is created using your provider.
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
---
|
||||
slug: /references/locking-service
|
||||
tags:
|
||||
- locking
|
||||
- server
|
||||
- how to
|
||||
sidebar_label: Use Locking Module
|
||||
---
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Use Locking Module
|
||||
|
||||
In this document, you’ll learn about the different methods in the Locking Module's service and how to use them.
|
||||
|
||||
---
|
||||
|
||||
## Resolve Locking Module's Service
|
||||
|
||||
In your workflow's step, you can resolve the Locking Module's service from the Medusa container:
|
||||
|
||||
```ts
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
import { createStep } from "@medusajs/framework/workflows-sdk"
|
||||
|
||||
const step1 = createStep(
|
||||
"step-1",
|
||||
async ({}, { container }) => {
|
||||
const lockingModuleService = container.resolve(
|
||||
Modules.LOCKING
|
||||
)
|
||||
|
||||
// TODO use lockingModuleService
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You can then use the Locking Module's service's methods in the step. The rest of this guide details these methods.
|
||||
|
||||
---
|
||||
|
||||
## execute
|
||||
|
||||
This method executes a giuven asynchronous job with a lock on the given keys. You can optionally pass a
|
||||
provider name to be used for locking. If no provider is passed, the default provider (in-memory or the
|
||||
provider configuerd in `medusa-config.ts`) will be used.
|
||||
|
||||
### Example
|
||||
|
||||
For example, to use the lock module when deleting a product:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.execute("prod_123", async () => {
|
||||
// assuming you've resolved the product service from the container
|
||||
await productModuleService.delete("prod_123")
|
||||
})
|
||||
```
|
||||
|
||||
In the above example, the product of ID `prod_123` is locked while it's being deleted.
|
||||
|
||||
To specify the provider to use for locking, you can pass the provider name in the `args` argument:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.execute("prod_123", async () => {
|
||||
// assuming you've resolved the product service from the container
|
||||
await productModuleService.delete("prod_123")
|
||||
}, {
|
||||
provider: "lp_my-lock"
|
||||
})
|
||||
```
|
||||
|
||||
### Type Parameters
|
||||
|
||||
<TypeList types={[{"name":"T","type":"`object`","description":"The type of the job's result.","optional":true,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to lock durng the job's execution.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"job","type":"() => Promise<T>","description":"The asynchronous job to execute while the keys are locked.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for the job execution.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"timeout","type":"`number`","description":"The timeout (in seconds) for acquiring the lock. If the time out is passed, the job is canceled and the lock is released.\nIts value defaults to `5` seconds if no value is passed or if you pass a value less than `1`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"provider","type":"`string`","description":"The provider name to use for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<T>","optional":false,"defaultValue":"","description":"The result of the job execution.","expandable":false,"children":[{"name":"T","type":"T","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
___
|
||||
|
||||
## acquire
|
||||
|
||||
This method acquires a lock on the given keys. You can optionally pass a provider name to be used for locking.
|
||||
If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.
|
||||
|
||||
You can pass an owner for the lock, which limits who can extend or release the acquired lock. Then, if you use this method again
|
||||
passing the same owner, the lock's expiration time is extended with the value passed in the `expire` argument. Otherwise, if you pass a
|
||||
different owner, the method throws an error.
|
||||
|
||||
### Example
|
||||
|
||||
For example, to acquire a lock on a product with ID `prod_123` for a user with ID `user_123`:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.acquire("prod_123", {
|
||||
ownerId: "user_123",
|
||||
expire: 60
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you acquire a lock on the product with ID `prod_123` for the user with ID `user_123`. You extend the
|
||||
lock's expiration time by `60` seconds.
|
||||
|
||||
To specify the provider to use for locking, you can pass the provider name in the `args` argument:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.acquire("prod_123", {
|
||||
ownerId: "user_123",
|
||||
expire: 60,
|
||||
provider: "lp_my-lock"
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to acquire the lock on.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for acquiring the lock.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The owner ID for the lock. If specified, only the owner can release the lock or extend its expiration time.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"expire","type":"`number`","description":"The expiration time (in seconds) for the lock. If the lock is already acquired and the owner is the same, the expiration time is extended\nby the value passed. If not specified, the lock does not expire.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"provider","type":"`string`","description":"The provider name to use for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="acquire"/>
|
||||
|
||||
### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"Resolves when the lock is acquired.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="acquire"/>
|
||||
|
||||
___
|
||||
|
||||
## release
|
||||
|
||||
This method releases a lock on the given keys. You can optionally pass a provider name to be used for locking.
|
||||
If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.
|
||||
|
||||
If the lock has an owner, you must pass the same owner to release the lock.
|
||||
|
||||
### Example
|
||||
|
||||
For example, to release a lock on a product with ID `prod_123` for a user with ID `user_123`:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.release("prod_123", {
|
||||
ownerId: "user_123"
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you release the lock on the product with ID `prod_123` for the user with ID `user_123`.
|
||||
|
||||
To specify the provider to use for locking, you can pass the provider name in the `args` argument:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.release("prod_123", {
|
||||
ownerId: "user_123",
|
||||
provider: "lp_my-lock"
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to release the lock from.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for releasing the lock.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The ID of the lock's owner. The lock can be released either if it doesn't have an owner, or \nif its owner ID matches the one passed in this property.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"provider","type":"`string`","description":"The provider name to use for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="release"/>
|
||||
|
||||
### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<boolean>","optional":false,"defaultValue":"","description":"Whether the lock was successfully released. If the lock has a different owner than the one passed, the method returns `false`.","expandable":false,"children":[{"name":"boolean","type":"`boolean`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="release"/>
|
||||
|
||||
___
|
||||
|
||||
## releaseAll
|
||||
|
||||
This method releases all locks. If you specify an owner ID, then all locks that the owner has acquired are released.
|
||||
|
||||
You can also pass a provider name to be used for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.
|
||||
|
||||
### Example
|
||||
|
||||
For example, to release all locks for a user with ID `user_123`:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.releaseAll({
|
||||
ownerId: "user_123"
|
||||
})
|
||||
```
|
||||
|
||||
In this example, you release all locks for the user with ID `user_123`.
|
||||
|
||||
To specify the provider to use for locking, you can pass the provider name in the `args` argument:
|
||||
|
||||
```ts
|
||||
await lockingModuleService.releaseAll({
|
||||
ownerId: "user_123",
|
||||
provider: "lp_my-lock"
|
||||
})
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<TypeList types={[{"name":"args","type":"`object`","description":"Additional arguments for releasing the locks.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The ID of a lock owner. If specified, all locks that the owner has acquired are released.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"provider","type":"`string`","description":"The provider name to use for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="releaseAll"/>
|
||||
|
||||
### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"This method releases all locks. If you specify an owner ID, then all locks that the owner has acquired are released.\n\nYou can also pass a provider name to be used for locking. If no provider is passed, the default provider (in-memory or the provider configuerd in `medusa-config.ts`) will be used.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="releaseAll"/>
|
||||
@@ -0,0 +1,440 @@
|
||||
---
|
||||
slug: /references/locking-module-provider
|
||||
tags:
|
||||
- locking
|
||||
- server
|
||||
- how to
|
||||
sidebar_label: Create Locking Provider
|
||||
---
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a Locking Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a Locking Module Provider and the methods you must implement in its main service.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Example
|
||||
|
||||
As you implement your Locking Module Provider, it can be useful to refer to an existing provider and how it's implemeted.
|
||||
|
||||
If you need to refer to an existing implementation as an example, check the [Redis Locking Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/locking-redis).
|
||||
|
||||
---
|
||||
|
||||
## 1. Create Module Provider Directory
|
||||
|
||||
Start by creating a new directory for your module provider.
|
||||
|
||||
If you're creating the module provider in a Medusa application, create it under the `src/modules` directory. For example, `src/modules/my-locking`.
|
||||
|
||||
If you're creating the module provider in a plugin, create it under the `src/providers` directory. For example, `src/providers/my-locking`.
|
||||
|
||||
<Note>
|
||||
|
||||
The rest of this guide always uses the `src/modules/my-locking` directory as an example.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Locking Module Provider Service
|
||||
|
||||
Create the file `src/modules/my-locking/service.ts` that holds the module provider's main service. It must implement the `ILockingProvider` interface imported from `@medusajs/framework/types`:
|
||||
|
||||
```ts title="src/modules/my-locking/service.ts"
|
||||
import { ILockingProvider } from "@medusajs/framework/types"
|
||||
|
||||
type Options = {
|
||||
url: string
|
||||
}
|
||||
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
// TODO implement methods
|
||||
}
|
||||
|
||||
export default MyLockingProviderService
|
||||
```
|
||||
|
||||
### constructor
|
||||
|
||||
The constructor allows you to access resources from the module's container using the first parameter,
|
||||
and the module's options using the second parameter.
|
||||
|
||||
If you're creating a client or establishing a connection with a third-party service, do it in the constructor.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
import { ILockingProvider } from "@medusajs/framework/types"
|
||||
import { Logger } from "@medusajs/framework/types"
|
||||
|
||||
type InjectedDependencies = {
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
type Options = {
|
||||
url: string
|
||||
}
|
||||
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
static identifier = "my-lock"
|
||||
protected logger_: Logger
|
||||
protected options_: Options
|
||||
// assuming you're initializing a client
|
||||
protected client
|
||||
|
||||
constructor (
|
||||
{ logger }: InjectedDependencies,
|
||||
options: Options
|
||||
) {
|
||||
this.logger_ = logger
|
||||
this.options_ = options
|
||||
|
||||
// assuming you're initializing a client
|
||||
this.client = new Client(options)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default MyLockingProviderService
|
||||
```
|
||||
|
||||
### Identifier
|
||||
|
||||
Every locking module provider must have an `identifier` static property. The provider's ID
|
||||
will be stored as `lp_{identifier}`.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
static identifier = "my-lock"
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### execute
|
||||
|
||||
This method executes a given asynchronous job with a lock on the given keys. The Locking Module uses this method
|
||||
when you call its `execute` method and your provider is the default provider, or you pass your provider's identifier to its `execute` method.
|
||||
|
||||
In the method, you should first try to acquire the lock on the given keys before the specified timeout passes.
|
||||
Then, once the lock is acquired, you execute the job. Otherwise, if the timeout passes before the lock is acquired, you cancel the job.
|
||||
|
||||
#### Example
|
||||
|
||||
An example of how to implement the `execute` method:
|
||||
|
||||
```ts
|
||||
// other imports...
|
||||
import { Context } from "@medusajs/framework/types"
|
||||
import { setTimeout } from "node:timers/promises"
|
||||
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
// ...
|
||||
async execute<T>(
|
||||
keys: string | string[],
|
||||
job: () => Promise<T>,
|
||||
args?: { timeout?: number },
|
||||
sharedContext?: Context
|
||||
): Promise<T> {
|
||||
// TODO you can add actions using the third-party client you initialized in the constructor
|
||||
const timeout = Math.max(args?.timeout ?? 5, 1)
|
||||
const timeoutSeconds = Number.isNaN(timeout) ? 1 : timeout
|
||||
const cancellationToken = { cancelled: false }
|
||||
const promises: Promise<any>[] = []
|
||||
|
||||
if (timeoutSeconds > 0) {
|
||||
promises.push(this.getTimeout(timeoutSeconds, cancellationToken))
|
||||
}
|
||||
|
||||
promises.push(
|
||||
this.acquire_(
|
||||
keys,
|
||||
{
|
||||
expire: args?.timeout ? timeoutSeconds : 0,
|
||||
},
|
||||
cancellationToken
|
||||
)
|
||||
)
|
||||
|
||||
await Promise.race(promises)
|
||||
|
||||
try {
|
||||
return await job()
|
||||
} finally {
|
||||
await this.release(keys)
|
||||
}
|
||||
}
|
||||
|
||||
private async getTimeout(
|
||||
seconds: number,
|
||||
cancellationToken: { cancelled: boolean }
|
||||
): Promise<void> {
|
||||
return new Promise(async (_, reject) => {
|
||||
await setTimeout(seconds * 1000)
|
||||
cancellationToken.cancelled = true
|
||||
reject(new Error("Timed-out acquiring lock."))
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, you first determine the timeout for acquiring the lock. You also create a `cancellationToken` object that you'll use to determine if the lock aquisition has timed out.
|
||||
|
||||
You then create an array of the following promises:
|
||||
|
||||
- A timeout promise that, if the lock acquisition takes longer than the timeout, sets the `cancelled` property of the `cancellationToken` object to `true`.
|
||||
- A promise that acquires the lock. You use a private `acquire_` method which you can find its implementation in the `aquire` method's example. If the first promise
|
||||
resolves and cancels the lock acquisition, the lock will not be acquired.
|
||||
|
||||
Finally, if the lock is acquired, you execute the job and release the lock after the job is done using the `release` method.
|
||||
|
||||
#### Type Parameters
|
||||
|
||||
<TypeList types={[{"name":"T","type":"`object`","description":"The type of the job's result.","optional":true,"defaultValue":"","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to lock during the job's execution.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"job","type":"() => Promise<T>","description":"The asynchronous job to execute while the keys are locked.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for the job execution.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"timeout","type":"`number`","description":"The timeout (in seconds) for acquiring the lock. If the time out is passed, the job is canceled and the lock is released.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<T>","optional":false,"defaultValue":"","description":"The result of the job.","expandable":false,"children":[{"name":"T","type":"T","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="execute"/>
|
||||
|
||||
### acquire
|
||||
|
||||
This method acquires a lock on the given keys. The Locking Module uses this method when you call its `acquire` method and your provider is the default provider,
|
||||
or you pass your provider's identifier to its `acquire` method.
|
||||
|
||||
In this method, you should only aquire the lock if the timeout hasn't passed. As explained in the [execute](page.mdx#execute) method's example,
|
||||
you can use a `cancellationToken` object to determine if the lock acquisition has timed out.
|
||||
|
||||
If the lock aquisition isn't canceled, you should aquire the lock, setting its expiry and owner. You should account for the following scenarios:
|
||||
|
||||
- The lock doesn't have an owner and you don't pass an owner, in which case the lock can be extended or released by anyone.
|
||||
- The lock doesn't have an owner or has the same owner that you pass, in which case you can extend the lock's expiration time and set the owner.
|
||||
- The lock has an owner, but you pass a different owner, in which case the method should throw an error.
|
||||
|
||||
#### Example
|
||||
|
||||
An example of how to implement the `acquire` method:
|
||||
|
||||
```ts
|
||||
type ResolvablePromise = {
|
||||
promise: Promise<any>
|
||||
resolve: () => void
|
||||
}
|
||||
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
// ...
|
||||
async acquire(
|
||||
keys: string | string[],
|
||||
args?: {
|
||||
ownerId?: string | null
|
||||
expire?: number
|
||||
awaitQueue?: boolean
|
||||
}
|
||||
): Promise<void> {
|
||||
return this.acquire_(keys, args)
|
||||
}
|
||||
|
||||
async acquire_(
|
||||
keys: string | string[],
|
||||
args?: {
|
||||
ownerId?: string | null
|
||||
expire?: number
|
||||
awaitQueue?: boolean
|
||||
},
|
||||
cancellationToken?: { cancelled: boolean }
|
||||
): Promise<void> {
|
||||
keys = Array.isArray(keys) ? keys : [keys]
|
||||
const { ownerId, expire } = args ?? {}
|
||||
|
||||
for (const key of keys) {
|
||||
if (cancellationToken?.cancelled) {
|
||||
throw new Error("Timed-out acquiring lock.")
|
||||
}
|
||||
|
||||
// assuming your client has this method and it validates the owner and expiration
|
||||
const result = await this.client.acquireLock(key, ownerId, expire)
|
||||
|
||||
if (result !== 1) {
|
||||
throw new Error(`Failed to acquire lock for key "${key}"`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, you add a private `acquire_` method that you use to acquire the lock. This method accepts an additional `cancellationToken` argument that you can use to determine if the lock acquisition has timed out.
|
||||
You can then use this method in other methods, such as the `execute` method.
|
||||
|
||||
In the `acquire_` method, you loop through the keys and try to acquire the lock on each key if the lock acquisition hasn't timed out. If the lock acquisition fails, you throw an error.
|
||||
This method assumes that the client you're integrating has a method called `acquireLock` that validates the owner and expiration time, and returns `1` if the lock is successfully acquired.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to acquire the lock on.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for acquiring the lock.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The ID of the lock's owner. If specified, only the owner can release the lock or extend its expiration time.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"expire","type":"`number`","description":"The expiration time (in seconds) for the lock. If the lock is already acquired and the owner is the same, the expiration time is extended\nby the value passed. If not specified, the lock does not expire.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="acquire"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"Resolves when the lock is acquired.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="acquire"/>
|
||||
|
||||
### release
|
||||
|
||||
This method releases a lock on the given keys. The Locking Module uses this method when you call its `release` method and your provider is the default provider,
|
||||
or you pass your provider's identifier to its `release` method.
|
||||
|
||||
In this method, you should release the lock on the given keys. If the lock has an owner, you should only release the lock if the owner is the same as the one passed.
|
||||
|
||||
#### Example
|
||||
|
||||
An example of how to implement the `release` method:
|
||||
|
||||
```ts
|
||||
// other imports...
|
||||
import { promiseAll } from "@medusajs/framework/utils"
|
||||
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
// ...
|
||||
async release(
|
||||
keys: string | string[],
|
||||
args?: { ownerId?: string | null },
|
||||
sharedContext?: Context
|
||||
): Promise<boolean> {
|
||||
const ownerId = args?.ownerId ?? "*"
|
||||
keys = Array.isArray(keys) ? keys : [keys]
|
||||
|
||||
const releasePromises = keys.map(async (key) => {
|
||||
// assuming your client has this method and it validates the owner
|
||||
const result = await this.client.releaseLock(key, ownerId)
|
||||
return result === 1
|
||||
})
|
||||
|
||||
const results = await promiseAll(releasePromises)
|
||||
|
||||
return results.every((released) => released)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, you loop through the keys and try to release the lock on each key using the client you're integrating. This implementation assumes that the client validates
|
||||
ownership of the lock and returns a result of `1` if the lock is successfully released.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"keys","type":"`string` \\| `string`[]","description":"The keys to release the lock from.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"args","type":"`object`","description":"Additional arguments for releasing the lock.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The ID of the lock's owner. The lock can be released either if it doesn't have an owner, or\nif its owner ID matches the one passed in this property.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="release"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<boolean>","optional":false,"defaultValue":"","description":"Whether the lock was successfully released. If the lock has a different owner than the one passed, the method returns `false`.","expandable":false,"children":[{"name":"boolean","type":"`boolean`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="release"/>
|
||||
|
||||
### releaseAll
|
||||
|
||||
This method releases all locks. The Locking Module uses this method when you call its `releaseAll` method and your provider is the default provider,
|
||||
or you pass your provider's identifier to its `releaseAll` method.
|
||||
|
||||
In this method, you should release all locks if no owner is passed. If an owner is passed, you should only release the locks that the owner has acquired.
|
||||
|
||||
#### Example
|
||||
|
||||
An example of how to implement the `releaseAll` method:
|
||||
|
||||
```ts
|
||||
class MyLockingProviderService implements ILockingProvider {
|
||||
// ...
|
||||
async releaseAll(
|
||||
args?: { ownerId?: string | null },
|
||||
sharedContext?: Context
|
||||
): Promise<void> {
|
||||
const ownerId = args?.ownerId ?? "*"
|
||||
|
||||
await this.client.releaseAllLock(ownerId)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, you release all locks either of all owners or the owner passed as an argument. This implementation assumes that the client you're integrating has a method called `releaseAllLock` that releases all locks
|
||||
for all owners or a specific owner.
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"args","type":"`object`","description":"Additional arguments for releasing the locks.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"ownerId","type":"`null` \\| `string`","description":"The ID of a lock owner. If specified, all locks that the owner has acquired are released.","optional":true,"defaultValue":"","expandable":false,"children":[]}]},{"name":"sharedContext","type":"[Context](../../../types/interfaces/types.Context/page.mdx)","description":"A context used to share resources, such as transaction manager, between the application and the module.","optional":true,"defaultValue":"","expandable":false,"children":[{"name":"transactionManager","type":"TManager","description":"An instance of a transaction manager of type `TManager`, which is a typed parameter passed to the context to specify the type of the `transactionManager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"manager","type":"TManager","description":"An instance of a manager, typically an entity manager, of type `TManager`, which is a typed parameter passed to the context to specify the type of the `manager`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationLevel","type":"`string`","description":"A string indicating the isolation level of the context. Possible values are `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, or `SERIALIZABLE`.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"enableNestedTransactions","type":"`boolean`","description":"A boolean value indicating whether nested transactions are enabled.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"eventGroupId","type":"`string`","description":"A string indicating the ID of the group to aggregate the events to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionId","type":"`string`","description":"A string indicating the ID of the current transaction.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"messageAggregator","type":"[IMessageAggregator](../../../types/interfaces/types.IMessageAggregator/page.mdx)","description":"An instance of a message aggregator, which is used to aggregate messages to be emitted at a later point.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"requestId","type":"`string`","description":"A string indicating the ID of the current request.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"idempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the current workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"parentStepIdempotencyKey","type":"`string`","description":"A string indicating the idempotencyKey of the parent workflow execution.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="releaseAll"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"This method releases all locks. The Locking Module uses this method when you call its `releaseAll` method and your provider is the default provider,\nor you pass your provider's identifier to its `releaseAll` method.\n\nIn this method, you should release all locks if no owner is passed. If an owner is passed, you should only release the locks that the owner has acquired.","expandable":false,"children":[]}]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="releaseAll"/>
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
|
||||
Create the file `src/modules/my-locking/index.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/my-locking/index.ts"
|
||||
import { ModuleProvider, Modules } from "@medusajs/framework/utils"
|
||||
import MyLockingProviderService from "./service"
|
||||
|
||||
export default ModuleProvider(Modules.LOCKING, {
|
||||
services: [MyLockingProviderService],
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module provider's definition, indicating that the `MyLockingProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Locking Module Provider, add it to the `providers` array of the Locking Module in `medusa-config.ts`:
|
||||
|
||||
```ts title="medusa-config.ts"
|
||||
module.exports = defineConfig({
|
||||
// ...
|
||||
modules: [
|
||||
{
|
||||
resolve: "@medusajs/medusa/payment",
|
||||
options: {
|
||||
providers: [
|
||||
{
|
||||
// if module provider is in a plugin, use `plugin-name/providers/my-locking`
|
||||
resolve: "./src/modules/my-locking",
|
||||
id: "my-lock",
|
||||
// set this if you want this provider to be used by default
|
||||
// and you have other Locking Module Providers registered.
|
||||
is_default: true,
|
||||
options: {
|
||||
url: "http://example.com",
|
||||
// provider options...
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Test it Out
|
||||
|
||||
When you start the Medusa application, if your Locking Module Provider is the only registered provider without enabling `is_default`, you'll see the following message:
|
||||
|
||||
```bash
|
||||
info: Locking module: Using "my-lock" as default.
|
||||
```
|
||||
|
||||
This indicates that your Locking Module Provider is being used as the default provider.
|
||||
|
||||
The Locking Module will now use your provider to handle all locking operations.
|
||||
|
||||
---
|
||||
|
||||
## Useful Guides
|
||||
|
||||
- [How to Use Locking Module](/references/locking-service)
|
||||
@@ -0,0 +1,8 @@
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# locking
|
||||
|
||||
## Interfaces
|
||||
|
||||
- [ILockingModule](../../locking/interfaces/locking.ILockingModule/page.mdx)
|
||||
- [ILockingProvider](../../locking/interfaces/locking.ILockingProvider/page.mdx)
|
||||
+15
-7
@@ -9,9 +9,17 @@ sidebar_label: Create Notification Provider
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a Notification Provider Module
|
||||
# How to Create a Notification Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a notification provider module and the methods you must implement in it.
|
||||
In this document, you’ll learn how to create a Notification Module Provider and the methods you must implement in it.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Example
|
||||
|
||||
As you implement your Notification Module Provider, it can be useful to refer to an existing provider and how it's implemeted.
|
||||
|
||||
If you need to refer to an existing implementation as an example, check the [SendGrid Notification Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/notification-sendgrid).
|
||||
|
||||
---
|
||||
|
||||
@@ -31,11 +39,11 @@ The rest of this guide always uses the `src/modules/my-notification` directory a
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Notification Provider Service
|
||||
## 2. Create the Notification Module Provider's Service
|
||||
|
||||
Create the file `src/modules/my-notification/service.ts` that holds the implementation of the notification service.
|
||||
|
||||
The Notification Provider Module's main service must extend the `AbstractNotificationProviderService` class imported from `@medusajs/framework/utils`:
|
||||
The Notification Module Provider's main service must extend the `AbstractNotificationProviderService` class imported from `@medusajs/framework/utils`:
|
||||
|
||||
```ts title="src/modules/my-notification/service.ts"
|
||||
import {
|
||||
@@ -172,7 +180,7 @@ class MyNotificationProviderService extends AbstractNotificationProviderService
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-notification/index.ts` with the following content:
|
||||
|
||||
@@ -188,11 +196,11 @@ export default ModuleProvider(Modules.NOTIFICATION, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyNotificationProviderService` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyNotificationProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Notification Module Provider, add it to the `providers` array of the Notification Module in `medusa-config.ts`:
|
||||
|
||||
|
||||
+21
-13
@@ -9,17 +9,25 @@ sidebar_label: Create Payment Provider
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a Payment Provider
|
||||
# How to Create a Payment Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a Payment Provider to be used with the Payment Module.
|
||||
In this document, you’ll learn how to create a Payment Module Provider to be used with the Payment Module.
|
||||
|
||||
---
|
||||
|
||||
## Understanding Payment Provider Implementation
|
||||
## Implementation Example
|
||||
|
||||
As you implement your Payment Module Provider, it can be useful to refer to an existing provider and how it's implemeted.
|
||||
|
||||
The Payment Module Provider handles processing payment with a third-party provirder. However, it's not responsible for managing payment concepts within Medusa, such as payment sessions or collections. These concepts are handled by the Payment Module which uses your payment provider within core operations.
|
||||
If you need to refer to an existing implementation as an example, check the [Stripe Payment Module Provider in the Medusa repository](https://github.com/medusajs/medusa/tree/develop/packages/modules/providers/payment-stripe).
|
||||
|
||||
For example, when the merchant captures an order's payment, the Payment Module uses the payment provider to capture the payment, the makes updates to the `Payment` record associated with the order. So, you only have to implement the third-party payment processing logic in your payment provider.
|
||||
---
|
||||
|
||||
## Understanding Payment Module Provider Implementation
|
||||
|
||||
The Payment Module Provider handles processing payment with a third-party provirder. However, it's not responsible for managing payment concepts within Medusa, such as payment sessions or collections. These concepts are handled by the Payment Module which uses your Payment Module Provider within core operations.
|
||||
|
||||
For example, when the merchant captures an order's payment, the Payment Module uses the Payment Module Provider to capture the payment, the makes updates to the `Payment` record associated with the order. So, you only have to implement the third-party payment processing logic in your Payment Module Provider.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,9 +47,9 @@ The rest of this guide always uses the `src/modules/my-payment` directory as an
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Payment Provider Service
|
||||
## 2. Create the Payment Module Provider's Service
|
||||
|
||||
Create the file `src/modules/my-payment/service.ts` that holds the module's main service. It must extend the `AbstractPaymentProvider` class imported from `@medusajs/framework/utils`:
|
||||
Create the file `src/modules/my-payment/service.ts` that holds the module provider's main service. It must extend the `AbstractPaymentProvider` class imported from `@medusajs/framework/utils`:
|
||||
|
||||
```ts title="src/modules/my-payment/service.ts"
|
||||
import { AbstractPaymentProvider } from "@medusajs/framework/utils"
|
||||
@@ -630,7 +638,7 @@ class MyPaymentProviderService extends AbstractPaymentProvider<
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-payment/index.ts` with the following content:
|
||||
|
||||
@@ -646,11 +654,11 @@ export default ModuleProvider(Modules.PAYMENT, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyPaymentProviderService` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyPaymentProviderService` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Payment Module Provider, add it to the `providers` array of the Payment Module in `medusa-config.ts`:
|
||||
|
||||
@@ -682,12 +690,12 @@ module.exports = defineConfig({
|
||||
|
||||
## 5. Test it Out
|
||||
|
||||
Before you use your payment provider, enable it in a region using the Medusa Admin.
|
||||
Before you use your Payment Module Provider, enable it in a region using the Medusa Admin.
|
||||
|
||||
Then, go through checkout to place an order. Your payment provider is used to authorize the payment.
|
||||
Then, go through checkout to place an order. Your Payment Module Provider is used to authorize the payment.
|
||||
|
||||
---
|
||||
|
||||
## Useful Guides
|
||||
|
||||
- [Storefront Guide: how to implement UI for your payment provider during checkout](https://docs.medusajs.com/resources/storefront-development/checkout/payment)
|
||||
- [Storefront Guide: how to implement UI for your Payment Module Provider during checkout](https://docs.medusajs.com/resources/storefront-development/checkout/payment)
|
||||
|
||||
+11
-11
@@ -9,23 +9,23 @@ sidebar_label: Create Tax Provider
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a Tax Provider
|
||||
# How to Create a Tax Module Provider
|
||||
|
||||
In this document, you’ll learn how to create a tax provider to use with the Tax Module, and the methods to implement.
|
||||
In this document, you’ll learn how to create a Tax Module Provider to use with the Tax Module, and the methods to implement.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A tax provider is used to retrieve the tax lines in a provided context. The Tax Module provides a default `system` provider. You can create your own tax provider, either in a plugin, in a module provider, or directly in your Medusa application's codebase, then use it in any tax region.
|
||||
A Tax Module Provider is used to retrieve the tax lines in a provided context. The Tax Module provides a default `system` provider. You can create your own Tax Module Provider, either in a plugin, in a module provider, or directly in your Medusa application's codebase, then use it in any tax region.
|
||||
|
||||
---
|
||||
|
||||
## Understanding Tax Provider Implementation
|
||||
## Understanding Tax Module Provider Implementation
|
||||
|
||||
The Tax Module Provider handles calculating taxes with a third-party provirder. However, it's not responsible for managing tax concepts within Medusa, such as creating a tax region. The Tax Module uses your tax provider within core operations.
|
||||
The Tax Module Provider handles calculating taxes with a third-party provirder. However, it's not responsible for managing tax concepts within Medusa, such as creating a tax region. The Tax Module uses your Tax Module Provider within core operations.
|
||||
|
||||
For example, during checkout, the tax provider of the tax region that the customer is in is used to calculate the tax for the cart and order. So, you only have to implement the third-party tax calculation logic in your tax provider.
|
||||
For example, during checkout, the Tax Module Provider of the tax region that the customer is in is used to calculate the tax for the cart and order. So, you only have to implement the third-party tax calculation logic in your Tax Module Provider.
|
||||
|
||||
---
|
||||
|
||||
@@ -45,9 +45,9 @@ The rest of this guide always uses the `src/modules/my-tax` directory as an exam
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the Tax Provider Service
|
||||
## 2. Create the Tax Module Provider's Service
|
||||
|
||||
Create the file `src/modules/my-tax/service.ts` that holds the module's main service. It must extend the `ITaxProvider` class imported from `@medusajs/framework/types`:
|
||||
Create the file `src/modules/my-tax/service.ts` that holds the module provider's main service. It must extend the `ITaxProvider` class imported from `@medusajs/framework/types`:
|
||||
|
||||
```ts title="src/modules/my-tax/service.ts"
|
||||
import { ITaxProvider } from "@medusajs/framework/types"
|
||||
@@ -156,7 +156,7 @@ export default class SystemTaxService implements ITaxProvider {
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
## 3. Create Module Provider Definition File
|
||||
|
||||
Create the file `src/modules/my-tax/index.ts` with the following content:
|
||||
|
||||
@@ -172,11 +172,11 @@ export default ModuleProvider(Modules.TAX, {
|
||||
})
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyTaxProvider` is the module's service.
|
||||
This exports the module provider's definition, indicating that the `MyTaxProvider` is the module provider's service.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
## 4. Use Module Provider
|
||||
|
||||
To use your Tax Module Provider, add it to the `providers` array of the Tax Module in `medusa-config.ts`:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user