diff --git a/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx b/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx index 136f935f88..637376bae1 100644 --- a/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx @@ -4,7 +4,8 @@ export const metadata = { # {metadata.title} -In this document, you’ll learn how about the different types of API keys, and their expiration and verification. +In this document, you’ll learn about the different types of API keys, their expiration and verification. + ## API Key Types There are two types of API keys: diff --git a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx index c0dabf6e45..fba3217080 100644 --- a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx @@ -13,13 +13,12 @@ In this guide, you’ll find common examples of how you can use the API Key Modu - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) @@ -68,13 +67,12 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) @@ -113,14 +111,13 @@ export async function GET(request: Request) { ```ts collapsibleLines="1-9" expandButtonLabel="Show Imports" import { AuthenticatedMedusaRequest, MedusaResponse } from "@medusajs/framework/http" -import { IApiKeyModuleService } from "@medusajs/framework/types" import { Modules } from "@medusajs/framework/utils" export async function POST( request: AuthenticatedMedusaRequest, res: MedusaResponse ) { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) @@ -172,13 +169,12 @@ export async function POST(request: Request, { params }: ContextType) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) @@ -229,19 +225,18 @@ export async function POST(request: Request, { params }: ContextType) { - ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" - import { - AuthenticatedMedusaRequest, - MedusaResponse, - } from "@medusajs/framework/http" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( request: AuthenticatedMedusaRequest, res: MedusaResponse ) { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) diff --git a/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx b/www/apps/resources/app/commerce-modules/api-key/links-to-other-modules/page.mdx similarity index 74% rename from www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx rename to www/apps/resources/app/commerce-modules/api-key/links-to-other-modules/page.mdx index 60abb27d57..3ef22327a6 100644 --- a/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/links-to-other-modules/page.mdx @@ -1,14 +1,14 @@ export const metadata = { - title: `Relations between API Key Module and Other Modules`, + title: `Links between API Key Module and Other Modules`, } # {metadata.title} -This document showcases the link modules defined between the API Key Module and other commerce modules. +This document showcases the module links defined between the API Key Module and other commerce modules. ## Sales Channel Module -You can create a publishable API key and associate it with a sales channel. Medusa defines a link module that builds a relation between the `ApiKey` and the `SalesChannel` data models. +You can create a publishable API key and associate it with a sales channel. Medusa defines a link between the `ApiKey` and the `SalesChannel` data models. ![A diagram showcasing an example of how data models from the API Key and Sales Channel modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1709812064/Medusa%20Resources/sales-channel-api-key_zmqi2l.jpg) diff --git a/www/apps/resources/app/commerce-modules/api-key/page.mdx b/www/apps/resources/app/commerce-modules/api-key/page.mdx index 0d6c4b8d62..cdb3f799df 100644 --- a/www/apps/resources/app/commerce-modules/api-key/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/page.mdx @@ -6,27 +6,42 @@ export const metadata = { # {metadata.title} -The API Key Module is the `@medusajs/medusa/api-key` NPM package that provides API-key-related features in your Medusa and Node.js applications. +The API Key Module provides API-key-related features in your Medusa and Node.js applications. ## How to Use API Key Module's Service -You can use the API Key Module's main service by resolving from the Medusa container the resource `Modules.API_KEY` imported from `@medusajs/framework/utils`. +Use the API Key Module's main service by resolving from the Medusa container the resource `Modules.API_KEY` imported from `@medusajs/framework/utils`. For example: + + +```ts title="src/workflows/hello-world/step1.ts" +import { createStep } from "@medusajs/framework/workflows-sdk" +import { Modules } from "@medusajs/framework/utils" + +const step1 = createStep("step-1", async (_, { container }) => { + const apiKeyModuleService = container.resolve( + Modules.API_KEY + ) + + const apiKeys = await apiKeyModuleService.listApiKeys() +}) +``` + + - ```ts title="src/api/store/custom/route.ts" - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts title="src/api/store/custom/route.ts" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function GET( request: MedusaRequest, res: MedusaResponse ): Promise { - const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( + const apiKeyModuleService = request.scope.resolve( Modules.API_KEY ) @@ -39,35 +54,17 @@ export async function GET( - ```ts title="src/subscribers/custom-handler.ts" - import { SubscriberArgs } from "@medusajs/framework" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts title="src/subscribers/custom-handler.ts" +import { SubscriberArgs } from "@medusajs/framework" +import { Modules } from "@medusajs/framework/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { - const apiKeyModuleService: IApiKeyModuleService = container.resolve( + const apiKeyModuleService = container.resolve( Modules.API_KEY ) const apiKeys = await apiKeyModuleService.listApiKeys() } -``` - - - - - ```ts title="src/workflows/hello-world/step1.ts" - import { createStep } from "@medusajs/framework/workflows-sdk" - import { IApiKeyModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" - -const step1 = createStep("step-1", async (_, { container }) => { - const apiKeyModuleService: IApiKeyModuleService = container.resolve( - Modules.API_KEY - ) - - const apiKeys = await apiKeyModuleService.listApiKeys() -}) ``` @@ -79,7 +76,7 @@ const step1 = createStep("step-1", async (_, { container }) => { ### API Key Types and Management -Store and manage API keys in your store. You can create both publishable and secret API keys for different use cases, such as: +Manage API keys in your store. You can create both publishable and secret API keys for different use cases, such as: - Publishable API Key associated with resources like sales channels. - Authentication token for admin users to access Admin API Routes. diff --git a/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx index b298186580..0b0eab7c64 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx @@ -8,19 +8,39 @@ In this document, you’ll learn about concepts related to identity and actors i ## What is an Auth Identity? -The [AuthIdentity data model](/references/auth/models/AuthIdentity) represents a registered user. +The [AuthIdentity data model](/references/auth/models/AuthIdentity) represents a user registered by an [authentication provider](../auth-providers/page.mdx). -When a user is registered, a record of `AuthIdentity` is created. This record is used to validate the user’s authentication in future requests. +When a user is registered using an authentication provider, it creates a record of `AuthIdentity`. + +Then, when the user logs-in in the future with the same authentication provider, the associated auth identity is used to validate their credentials. --- ## Actor Types -An actor type is a type of user that can be authenticated. This user is a record of a data model defined by a module. +An actor type is a type of user that can be authenticated. -For example, the `customer` actor type belongs to the Customer Module’s `Customer` data model. Similarly, the `user` actor type belongs to the User Module’s `User` data model. +The Auth Module doesn't store or manage any user-like models, such as for customers or users. -### Protect Routes by Actor Type +Instead, the user types are created and managed by other modules. For example, a customer is managed by the Customer Module. + +Then, when an auth identity is created for the actor type, the ID of the user is stored in the `app_metadata` property of the auth identity. + +For example, an auth identity of a customer has the following `app_metadata` property: + +```json +{ + "app_metadata": { + "customer_id": "cus_123" + } +} +``` + +The ID of the user is stored in the key `{actor_type}_id` of the `app_metadata` property. + +--- + +## Protect Routes by Actor Type When you protect routes with the `authenticate` middleware, you specify in its first parameter the actor type that must be authenticated to access the specified API routes. @@ -54,7 +74,7 @@ By specifying `user` as the first parameter of `authenticate`, only authenticate ## Custom Actor Types -You can define custom actor types that point to the data model of your module. +You can define custom actor types that allows a custom user, managed by your custom module, to authenticate into Medusa. For example, if you have a custom module with a `Manager` data model, you can authenticate managers with the `manager` actor type. diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx index 4a0cef2c82..1eba284ab0 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx @@ -88,6 +88,8 @@ const modules = { +--- + ## Related Guides - [How to register a customer using email and password](../../../../storefront-development/customers/register/page.mdx) diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx index 24e3f02632..26350fde8b 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx @@ -8,7 +8,7 @@ export const metadata = { In this document, you’ll learn about the GitHub Auth Module Provider and how to install and use it in the Auth Module. -The Github Auth Module Provider handles authenticating users with their GitHub account. +The Github Auth Module Provider authenticates users with their GitHub account. diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx index ee7df1eb9b..4c689c4fcd 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx @@ -8,11 +8,11 @@ export const metadata = { In this document, you’ll learn about the Google Auth Module Provider and how to install and use it in the Auth Module. -The Google Auth Module Provider handles authenticating users with their Google account. +The Google Auth Module Provider authenticates users with their Google account. -Learn about the authentication flow in [this guide](../../authentication-route/page.mdx). +Learn about the authentication flow for third-party providers in [this guide](../../authentication-route/page.mdx#2-third-party-service-authenticate-flow). @@ -143,4 +143,4 @@ GOOGLE_CALLBACK_URL= ## Examples -- [How to implement Google social login in the storefront.](../../../../storefront-development/customers/third-party-login/page.mdx). +- [How to implement Google social login in the storefront](../../../../storefront-development/customers/third-party-login/page.mdx). diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx index ebde6f8c41..5551b6b2da 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx @@ -37,7 +37,7 @@ For example, the EmailPass Auth Module Provider authenticates a user using their ## Configure Allowed Auth Providers of Actor Types -By default, users of all actor types can authenticate with all installed auth module providerss. +By default, users of all actor types can authenticate with all installed auth module providers. To restrict the auth providers used for actor types, use the [authMethodsPerActor option](/references/medusa-config#http-authMethodsPerActor-1-3) in Medusa's configurations: diff --git a/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx b/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx index 44a80d9088..a190e10bb8 100644 --- a/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx @@ -8,7 +8,13 @@ In this document, learn how to create an actor type and authenticate its associa ## 0. Create Module with Data Model -Before creating an actor type, you must define a data model the actor type belongs to. The data model is defined in a custom module. +Before creating an actor type, you must have a module with a data model representing the actor type. + + + +Learn how to create a module in [this guide](!docs!/basics/modules). + + The rest of this guide uses this `Manager` data model as an example: @@ -31,7 +37,7 @@ export default Manager Start by creating a workflow that does two things: -- Create a record of the `Manager` data model. +- Creates a record of the `Manager` data model. - Sets the `app_metadata` property of the associated `AuthIdentity` record based on the new actor type. For example, create the file `src/workflows/create-manager.ts`. with the following content: diff --git a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx index a909d7bed2..84948e8e92 100644 --- a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx @@ -19,21 +19,21 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j - ```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { - IAuthModuleService, - AuthenticationInput, - } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" - import { MedusaError } from "@medusajs/framework/utils" - import jwt from "jsonwebtoken" +```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { + IAuthModuleService, + AuthenticationInput, +} from "@medusajs/framework/types" +import { Modules } from "@medusajs/framework/utils" +import { MedusaError } from "@medusajs/framework/utils" +import jwt from "jsonwebtoken" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -122,21 +122,21 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j - ```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { - IAuthModuleService, - AuthenticationInput, - } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" - import { MedusaError } from "@medusajs/framework/utils" - import jwt from "jsonwebtoken" +```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { + IAuthModuleService, + AuthenticationInput, +} from "@medusajs/framework/types" +import { Modules } from "@medusajs/framework/utils" +import { MedusaError } from "@medusajs/framework/utils" +import jwt from "jsonwebtoken" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -224,16 +224,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IAuthModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -280,16 +279,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IAuthModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -327,15 +325,14 @@ export async function GET(request: Request) { ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IAuthModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -393,15 +390,14 @@ export async function POST(request: Request, { params }: ContextType) { ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { IAuthModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function DELETE( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) diff --git a/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx b/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx index bb1cb41211..8d408ef084 100644 --- a/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx @@ -18,6 +18,12 @@ The `providers` option is an array of auth module providers. When the Medusa application starts, these providers are registered and can be used to handle authentication. + + +By default, the `emailpass` provider is registered to authenticate customers and admin users. + + + For example: ```js title="medusa-config.js" @@ -46,7 +52,7 @@ module.exports = defineConfig({ The `providers` option is an array of objects that accept the following properties: -- `resolve`: A string indicating the package name of the module provider or the path to it. +- `resolve`: A string indicating the package name of the module provider or the path to it relative to the `src` directory. - `id`: A string indicating the provider's unique name or ID. - `options`: An optional object of the module provider's options. @@ -54,9 +60,11 @@ The `providers` option is an array of objects that accept the following properti ## Auth CORS -The Medusa application's authentication API routes are defined under the `/auth` prefix that requires setting the `authCors` property of the `http` configuration. So, before using these routes, make sure to set that configuration. +The Medusa application's authentication API routes are defined under the `/auth` prefix that requires setting the `authCors` property of the `http` configuration. -Refer to [Medusa's configuration guide](/references/medusa-config#authCors) for more details. +By default, the Medusa application you created will have an `AUTH_CORS` environment variable, which is used as the value of `authCors`. + +Refer to [Medusa's configuration guide](/references/medusa-config#authCors) to learn more about the `authCors` configuration. --- @@ -64,4 +72,4 @@ Refer to [Medusa's configuration guide](/references/medusa-config#authCors) for The Medusa application's configuration accept an `authMethodsPerActor` configuration which restricts the allowed auth providers used with an actor type. -Learn more about the `authMethodsPerActor` configuration in [this guide](../auth-providers/page.mdx#configure-allowed-auth-providers-of-actor-types). \ No newline at end of file +Learn more about the `authMethodsPerActor` configuration in [this guide](../auth-providers/page.mdx#configure-allowed-auth-providers-of-actor-types). diff --git a/www/apps/resources/app/commerce-modules/auth/page.mdx b/www/apps/resources/app/commerce-modules/auth/page.mdx index cbdbc2ca5c..7ed218e34c 100644 --- a/www/apps/resources/app/commerce-modules/auth/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/page.mdx @@ -6,27 +6,41 @@ export const metadata = { # {metadata.title} -The Auth Module is the `@medusajs/medusa/auth` NPM package that provides authentication-related features in your Medusa and Node.js applications. +The Auth Module provides authentication-related features in your Medusa and Node.js applications. ## How to Use Auth Module's Service -You can use the Auth Module's main service by resolving from the Medusa container the resource `Modules.AUTH` imported from `@medusajs/framework/utils`. +Use the Auth Module's main service by resolving from the Medusa container the resource `Modules.AUTH` imported from `@medusajs/framework/utils`. For example: + + +```ts title="src/workflows/hello-world/step1.ts" +import { createStep } from "@medusajs/framework/workflows-sdk" +import { Modules } from "@medusajs/framework/utils" + +const step1 = createStep("step-1", async (_, { container }) => { + const authModuleService = container.resolve( + Modules.AUTH + ) + const authIdentitys = await authModuleService.listAuthIdentities() +}) +``` + + ```ts title="src/api/store/custom/route.ts" import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" -import { IAuthModuleService } from "@medusajs/framework/types" import { Modules } from "@medusajs/framework/utils" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { - const authModuleService: IAuthModuleService = req.scope.resolve( + const authModuleService = req.scope.resolve( Modules.AUTH ) @@ -41,32 +55,15 @@ export async function GET( ```ts title="src/subscribers/custom-handler.ts" import { SubscriberArgs } from "@medusajs/framework" -import { IAuthModuleService } from "@medusajs/framework/types" import { Modules } from "@medusajs/framework/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { - const authModuleService: IAuthModuleService = container.resolve( + const authModuleService = container.resolve( Modules.AUTH ) const authIdentitys = await authModuleService.listAuthIdentities() } -``` - - - - -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/framework/workflows-sdk" -import { IAuthModuleService } from "@medusajs/framework/types" -import { Modules } from "@medusajs/framework/utils" - -const step1 = createStep("step-1", async (_, { container }) => { - const authModuleService: IAuthModuleService = container.resolve( - Modules.AUTH - ) - const authIdentitys = await authModuleService.listAuthIdentities() -}) ``` @@ -78,7 +75,7 @@ const step1 = createStep("step-1", async (_, { container }) => { ### Basic User Authentication -With the Auth Module, authenticate users using their email and password credentials. +Authenticate users using their email and password credentials. ```ts const { success, authIdentity, error } = await authModuleService.authenticate( diff --git a/www/apps/resources/app/commerce-modules/auth/reset-password/page.mdx b/www/apps/resources/app/commerce-modules/auth/reset-password/page.mdx index aa188af0df..432d0036c0 100644 --- a/www/apps/resources/app/commerce-modules/auth/reset-password/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/reset-password/page.mdx @@ -6,7 +6,9 @@ export const metadata = { # {metadata.title} -In this guide, you'll learn how to handle the `auth.password_reset` event, which is emitted when a request is sent to the [Generate Reset Password Token API route](../authentication-route/page.mdx#generate-reset-password-token-route), to send reset instructions to the user. +In this guide, you'll learn how to handle the `auth.password_reset` event, which is emitted when a request is sent to the [Generate Reset Password Token API route](../authentication-route/page.mdx#generate-reset-password-token-route). + +You'll create a subscriber that listens to the event. When the event is emitted, the subscriber sends an email notification to the user. -A product variant can be from the [Product Module](../../product/page.mdx) but can also be a custom item used only in this cart. +In the Medusa application, a product variant is implemented in the [Product Module](../../product/page.mdx). @@ -32,12 +32,12 @@ A product variant can be from the [Product Module](../../product/page.mdx) but c A shipping method, represented by the [ShippingMethod data model](/references/cart/models/ShippingMethod), is used to fulfill the items in the cart after the order is placed. A cart can have more than one shipping method. -If the shipping method is created from a shipping option, available through the [Fulfillment Module](../../fulfillment/page.mdx), its ID is stored in the `shipping_option_id`. - -A shipping method can also be a custom method associated with this cart only. +In the Medusa application, the shipping method is created from a shipping option, available through the [Fulfillment Module](../../fulfillment/page.mdx). Its ID is stored in the `shipping_option_id` property of the method. ### data Property -After an order is placed, you may use a third-party fulfillment provider to fulfill its shipments. If the fulfillment provider requires additional custom data to be passed along from the checkout process, you can add this data in the `ShippingMethod`'s `data` property. +After an order is placed, you can use a third-party fulfillment provider to fulfill its shipments. + +If the fulfillment provider requires additional custom data to be passed along from the checkout process, set this data in the `ShippingMethod`'s `data` property. The `data` property is an object used to store custom data relevant later for fulfillment. diff --git a/www/apps/resources/app/commerce-modules/cart/examples/page.mdx b/www/apps/resources/app/commerce-modules/cart/examples/page.mdx index ad49fc3e8e..3663ea3f65 100644 --- a/www/apps/resources/app/commerce-modules/cart/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/examples/page.mdx @@ -13,16 +13,15 @@ In this guide, you’ll find common examples of how you can use the Cart Module - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -87,16 +86,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -135,16 +133,15 @@ export async function GET(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -195,16 +192,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -253,16 +249,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -311,16 +306,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function POST( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -371,16 +365,15 @@ export async function POST(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function DELETE( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -415,16 +408,15 @@ export async function DELETE(request: Request) { - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function DELETE( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -437,16 +429,15 @@ export async function DELETE( - ```ts - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function DELETE( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) diff --git a/www/apps/resources/app/commerce-modules/cart/extend/page.mdx b/www/apps/resources/app/commerce-modules/cart/extend/page.mdx new file mode 100644 index 0000000000..72c9c9ee59 --- /dev/null +++ b/www/apps/resources/app/commerce-modules/cart/extend/page.mdx @@ -0,0 +1,666 @@ +import { Prerequisites } from "docs-ui" + +export const metadata = { + title: `Extend Cart Data Model`, +} + +# {metadata.title} + +In this documentation, you'll learn how to extend a data model of the Cart Module to add a custom property. + +You'll create a `Custom` data model in a module. This data model will have a `custom_name` property, which is the property you want to add to the [Cart data model](/references/cart/models/Cart) defined in the Cart Module. + +You'll then learn how to: + +- Link the `Custom` data model to the `Cart` data model. +- Set the `custom_name` property when a cart is created or updated using Medusa's API routes. +- Retrieve the `custom_name` property with the cart's details, in custom or existing API routes. + +## Step 1: Define Custom Data Model + +Consider you have a Hello Module defined in the `/src/modules/hello` directory. + + + +If you don't have a module, follow [this guide](!docs!/basics/modules) to create one. + + + +To add the `custom_name` property to the `Cart` data model, you'll create in the Hello Module a data model that has the `custom_name` property. + +Create the file `src/modules/hello/models/custom.ts` with the following content: + +```ts title="src/modules/hello/models/custom.ts" +import { model } from "@medusajs/framework/utils" + +export const Custom = model.define("custom", { + id: model.id().primaryKey(), + custom_name: model.text(), +}) +``` + +This creates a `Custom` data model that has the `id` and `custom_name` properties. + + + +Learn more about data models in [this guide](!docs!/data-models). + + + +--- + +## Step 2: Define Link to Cart Data Model + +Next, you'll define a module link between the `Custom` and `Cart` data model. A module link allows you to form a relation between two data models of separate modules while maintaining module isolation. + + + +Learn more about module links in [this guide](!docs!/module-links). + + + +Create the file `src/links/cart-custom.ts` with the following content: + +```ts title="src/links/cart-custom.ts" +import { defineLink } from "@medusajs/framework/utils" +import HelloModule from "../modules/hello" +import CartModule from "@medusajs/medusa/cart" + +export default defineLink( + CartModule.linkable.cart, + HelloModule.linkable.custom +) +``` + +This defines a link between the `Cart` and `Custom` data models. Using this link, you'll later query data across the modules, and link records of each data model. + +--- + +## Step 3: Generate and Run Migrations + + + +To reflect the `Custom` data model in the database, generate a migration that defines the table to be created for it. + +Run the following command in your Medusa project's root: + +```bash +npx medusa db:generate helloModuleService +``` + +Where `helloModuleService` is your module's name. + +Then, run the `db:migrate` command to run the migrations and create a table in the database for the link between the `Cart` and `Custom` data models: + +```bash +npx medusa db:migrate +``` + +A table for the link is now created in the database. You can now retrieve and manage the link between records of the data models. + +--- + +## Step 4: Consume cartCreated Workflow Hook + +When a cart is created, you also want to create a `Custom` record and set the `custom_name` property, then create a link between the `Cart` and `Custom` records. + +To do that, you'll consume the [cartCreated](/references/medusa-workflows/createCartWorkflow#cartcreated) hook of the [createCartWorkflow](/references/medusa-workflows/createCartWorkflow). This workflow is executed in the [Create Cart API Route](!api!/store#carts_postcarts). + + + +Learn more about workflow hooks in [this guide](!docs!/advanced-development/workflows/workflow-hooks). + + + +The API route accepts in its request body an `additional_data` parameter. You can pass in it custom data, which is passed to the workflow hook handler. + +### Add custom_name to Additional Data Validation + +To pass the `custom_name` in the `additional_data` parameter, you must add a validation rule that tells the Medusa application about this custom property. + +Create the file `src/api/middlewares.ts` with the following content: + +```ts title="src/api/middlewares.ts" +import { defineMiddlewares } from "@medusajs/medusa" +import { z } from "zod" + +export default defineMiddlewares({ + routes: [ + { + method: "POST", + matcher: "/store/carts", + additionalDataValidator: { + custom_name: z.string().optional(), + }, + }, + ], +}) +``` + +The `additional_data` parameter validation is customized using the `defineMiddlewares` utility function. In the routes middleware configuration object, the `additionalDataValidator` property accepts [Zod](https://zod.dev/) validaiton rules. + +In the snippet above, you add a validation rule indicating that `custom_name` is a string that can be passed in the `additional_data` object. + + + +Learn more about additional data validation in [this guide](!docs!/advanced-development/api-routes/additional-data). + + + +### Create Workflow to Create Custom Record + +You'll now create a workflow that will be used in the hook handler. + +This workflow will create a `Custom` record, then link it to the cart. + +Start by creating the step that creates the `Custom` record. Create the file `src/workflows/create-custom-from-cart/steps/create-custom.ts` with the following content: + +```ts title="src/workflows/create-custom-from-cart/steps/create-custom.ts" +import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" +import HelloModuleService from "../../../modules/hello/service" +import { HELLO_MODULE } from "../../../modules/hello" + +type CreateCustomStepInput = { + custom_name?: string +} + +export const createCustomStep = createStep( + "create-custom", + async (data: CreateCustomStepInput, { container }) => { + if (!data.custom_name) { + return + } + + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + const custom = await helloModuleService.createCustoms(data) + + return new StepResponse(custom, custom) + }, + async (custom, { container }) => { + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + await helloModuleService.deleteCustoms(custom.id) + } +) +``` + +In the step, you resolve the Hello Module's main service and create a `Custom` record. + +In the compensation function that undoes the step's actions in case of an error, you delete the created record. + + + +Learn more about compensation functions in [this guide](!docs!/advanced-development/workflows/compensation-function). + + + +Then, create the workflow at `src/workflows/create-custom-from-cart/index.ts` with the following content: + +```ts title="src/workflows/create-custom-from-cart/index.ts" collapsibleLines="1-7" expandButtonLabel="Show Imports" +import { createWorkflow, transform, when, WorkflowResponse } from "@medusajs/framework/workflows-sdk" +import { CartDTO } from "@medusajs/framework/types" +import { createCustomStep } from "./steps/create-custom" +import { createRemoteLinkStep } from "@medusajs/medusa/core-flows" +import { Modules } from "@medusajs/framework/utils" +import { HELLO_MODULE } from "../../modules/hello" + +export type CreateCustomFromCartWorkflowInput = { + cart: CartDTO + additional_data?: { + custom_name?: string + } +} + +export const createCustomFromCartWorkflow = createWorkflow( + "create-custom-from-cart", + (input: CreateCustomFromCartWorkflowInput) => { + const customName = transform( + { + input, + }, + (data) => data.input.additional_data?.custom_name || "" + ) + + const custom = createCustomStep({ + custom_name: customName, + }) + + when(({ custom }), ({ custom }) => custom !== undefined) + .then(() => { + createRemoteLinkStep([{ + [Modules.CART]: { + cart_id: input.cart.id, + }, + [HELLO_MODULE]: { + custom_id: custom.id, + }, + }]) + }) + + return new WorkflowResponse({ + custom, + }) + } +) +``` + +The workflow accepts as an input the created cart and the `additional_data` parameter passed in the request. This is the same input that the `cartCreated` hook accepts. + +In the workflow, you: + +1. Use the `transform` utility to get the value of `custom_name` based on whether it's set in `additional_data`. Learn more about why you can't use conditional operators in a workflow without using `transform` in [this guide](!docs!/advanced-development/workflows/conditions#why-if-conditions-arent-allowed-in-workflows). +2. Create the `Custom` record using the `createCustomStep`. +3. Use the `when-then` utility to link the cart to the `Custom` record if it was created. Learn more about why you can't use if-then conditions in a workflow without using `when-then` in [this guide](!docs!/advanced-development/workflows/conditions#why-if-conditions-arent-allowed-in-workflows). + +You'll next call the workflow in the hook handler. + +### Consume Workflow Hook + +You can now consume the `cartCreated` hook, which is executed in the `createCartWorkflow` after the cart is created. + +To consume the hook, create the file `src/workflow/hooks/cart-created.ts` with the following content: + +```ts title="src/workflow/hooks/cart-created.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports" +import { createCartWorkflow } from "@medusajs/medusa/core-flows" +import { + createCustomFromCartWorkflow, + CreateCustomFromCartWorkflowInput, +} from "../create-custom-from-cart" + +createCartWorkflow.hooks.cartCreated( + async (hookData, { container }) => { + await createCustomFromCartWorkflow(container) + .run({ + input: hookData as CreateCustomFromCartWorkflowInput, + }) + } +) +``` + +The hook handler executes the `createCustomFromCartWorkflow`, passing it its input. + +### Test it Out + +To test it out, send a `POST` request to `/store/carts` to create a cart, passing `custom_name` in `additional_data`: + +```bash +curl -X POST 'localhost:9000/store/carts' \ +-H 'x-publishable-api-key: {publishable_api_key}' \ +-H 'Content-Type: application/json' \ +--data '{ + "region_id": "reg_01J9NNNWVV0T71PT44EAMTJCMP", + "additional_data": { + "custom_name": "test" + } +}' +``` + +Make sure to replace `{publishable_api_key}` with your publishable API key, which you can retrieve from the Medusa Admin. Also, replace the value of `region_id` with an ID of a region in your application. + +The request will return the cart's details. You'll learn how to retrive the `custom_name` property with the cart's details in the next section. + +--- + +## Step 5: Retrieve custom_name with Cart Details + +When you extend an existing data model through links, you also want to retrieve the custom properties with the data model. + +### Retrieve in API Routes + +To retrieve the `custom_name` property when you're retrieving the cart through API routes, such as the [Get Cart API Route](!api!/store#carts_getcartsid), pass in the `fields` query parameter `+custom.*`, which retrieves the linked `Custom` record's details. + + + +The `+` prefix in `+custom.*` indicates that the relation should be retrieved with the default cart fields. Learn more about selecting fields and relations in the [API reference](!api!/store#select-fields-and-relations). + + + +For example: + +```bash +curl -X POST 'localhost:9000/store/carts/{cart_id}?fields=+custom.*' \ +-H 'x-publishable-api-key: {publishable_api_key}' +``` + +Make sure to replace `{cart_id}` with the cart's ID, and `{publishable_api_key}` with your publishable API key, which you can retrieve from the Medusa Admin. + +Among the returned `cart` object, you'll find a `custom` property which holds the details of the linked `Custom` record: + +```json +{ + "cart": { + // ... + "custom": { + "id": "01J9NP7ANXDZ0EAYF0956ZE1ZA", + "custom_name": "test", + "created_at": "2024-10-08T09:09:06.877Z", + "updated_at": "2024-10-08T09:09:06.877Z", + "deleted_at": null + } + } +} +``` + +### Retrieve using Query + +You can also retrieve the `Custom` record linked to a cart in your code using [Query](!docs!/advanced-development/module-links/query). + +For example: + +```ts +const { data: [cart] } = await query.graph({ + entity: "cart", + fields: ["*", "custom.*"], + filters: { + id: cart_id, + }, +}) +``` + +Learn more about how to use Query in [this guide](!docs!/advanced-development/module-links/query). + +--- + +## Step 6: Consume cartUpdated Workflow Hook + +Similar to the `cartCreated` hook, you'll consume the [cartUpdated](/references/medusa-workflows/updateCartWorkflow#cartupdated) hook of the [updateCartWorkflow](/references/medusa-workflows/updateCartWorkflow) to update `custom_name` when the cart is updated. + +The `updateCartWorkflow` is executed by the [Update Cart API route](!api!/store#carts_postcartsid), which accepts the `additional_data` parameter to pass custom data to the hook. + +### Add custom_name to Additional Data Validation + +To allow passing `custom_name` in the `additional_data` parameter of the update cart route, add in `src/api/middlewares.ts` a new route middleware configuration object: + +```ts title="src/api/middlewares.ts" +import { defineMiddlewares } from "@medusajs/medusa" +import { z } from "zod" + +export default defineMiddlewares({ + routes: [ + // ... + { + method: "POST", + matcher: "/store/carts/:id", + additionalDataValidator: { + custom_name: z.string().nullish(), + }, + }, + ], +}) +``` + +The validation schema is the similar to that of the Create Cart API route, except you can pass a `null` value for `custom_name` to remove or unset the `custom_name`'s value. + +### Create Workflow to Update Custom Record + +Next, you'll create a workflow that creates, updates, or deletes `Custom` records based on the provided `additional_data` parameter: + +1. If `additional_data.custom_name` is set and it's `null`, the `Custom` record linked to the cart is deleted. +2. If `additional_data.custom_name` is set and the cart doesn't have a linked `Custom` record, a new record is created and linked to the cart. +3. If `additional_data.custom_name` is set and the cart has a linked `Custom` record, the `custom_name` property of the `Custom` record is updated. + +Start by creating the step that updates a `Custom` record. Create the file `src/workflows/update-custom-from-cart/steps/update-custom.ts` with the following content: + +```ts title="src/workflows/update-custom-from-cart/steps/update-custom.ts" +import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" +import { HELLO_MODULE } from "../../../modules/hello" +import HelloModuleService from "../../../modules/hello/service" + +type UpdateCustomStepInput = { + id: string + custom_name: string +} + +export const updateCustomStep = createStep( + "update-custom", + async ({ id, custom_name }: UpdateCustomStepInput, { container }) => { + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + const prevData = await helloModuleService.retrieveCustom(id) + + const custom = await helloModuleService.updateCustoms({ + id, + custom_name, + }) + + return new StepResponse(custom, prevData) + }, + async (prevData, { container }) => { + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + await helloModuleService.updateCustoms(prevData) + } +) +``` + +In this step, you update a `Custom` record. In the compensation function, you revert the update. + +Next, you'll create the step that deletes a `Custom` record. Create the file `src/workflows/update-custom-from-cart/steps/delete-custom.ts` with the following content: + +```ts title="src/workflows/update-custom-from-cart/steps/delete-custom.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports" +import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" +import { Custom } from "../../../modules/hello/models/custom" +import { InferTypeOf } from "@medusajs/framework/types" +import HelloModuleService from "../../../modules/hello/service" +import { HELLO_MODULE } from "../../../modules/hello" + +type DeleteCustomStepInput = { + custom: InferTypeOf +} + +export const deleteCustomStep = createStep( + "delete-custom", + async ({ custom }: DeleteCustomStepInput, { container }) => { + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + await helloModuleService.deleteCustoms(custom.id) + + return new StepResponse(custom, custom) + }, + async (custom, { container }) => { + const helloModuleService: HelloModuleService = container.resolve( + HELLO_MODULE + ) + + await helloModuleService.createCustoms(custom) + } +) +``` + +In this step, you delete a `Custom` record. In the compensation function, you create it again. + +Finally, you'll create the workflow. Create the file `src/workflows/update-custom-from-cart/index.ts` with the following content: + +```ts title="src/workflows/update-custom-from-cart/index.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports" +import { CartDTO } from "@medusajs/framework/types" +import { createWorkflow, when, WorkflowResponse } from "@medusajs/framework/workflows-sdk" +import { createRemoteLinkStep, dismissRemoteLinkStep, useRemoteQueryStep } from "@medusajs/medusa/core-flows" +import { createCustomStep } from "../create-custom-from-cart/steps/create-custom" +import { Modules } from "@medusajs/framework/utils" +import { HELLO_MODULE } from "../../modules/hello" +import { deleteCustomStep } from "./steps/delete-custom" +import { updateCustomStep } from "./steps/update-custom" + +export type UpdateCustomFromCartStepInput = { + cart: CartDTO + additional_data?: { + custom_name?: string | null + } +} + +export const updateCustomFromCartWorkflow = createWorkflow( + "update-custom-from-cart", + (input: UpdateCustomFromCartStepInput) => { + const cartData = useRemoteQueryStep({ + entry_point: "cart", + fields: ["custom.*"], + variables: { + filters: { + id: input.cart.id, + }, + }, + list: false, + }) + + // TODO create, update, or delete Custom record + } +) +``` + +The workflow accepts the same input as the `cartUpdated` workflow hook handler would. + +In the workflow, you retrieve the cart's linked `Custom` record using Query. + +Next, replace the `TODO` with the following: + +```ts title="src/workflows/update-custom-from-cart/index.ts" +const created = when({ + input, + cartData, +}, (data) => + !data.cartData.custom && + data.input.additional_data?.custom_name?.length > 0 +) +.then(() => { + const custom = createCustomStep({ + custom_name: input.additional_data.custom_name, + }) + + createRemoteLinkStep([{ + [Modules.CART]: { + cart_id: input.cart.id, + }, + [HELLO_MODULE]: { + custom_id: custom.id, + }, + }]) + + return custom +}) + +// TODO update, or delete Custom record +``` + +Using the `when-then` utility, you check if the cart doesn't have a linked `Custom` record and the `custom_name` property is set. If so, you create a `Custom` record and link it to the cart. + +To create the `Custom` record, you use the `createCustomStep` you created in an earlier section. + +Next, replace the new `TODO` with the following: + +```ts title="src/workflows/update-custom-from-cart/index.ts" +const deleted = when({ + input, + cartData, +}, (data) => + data.cartData.custom && ( + data.input.additional_data?.custom_name === null || + data.input.additional_data?.custom_name.length === 0 + ) +) +.then(() => { + deleteCustomStep({ + custom: cartData.custom, + }) + + dismissRemoteLinkStep({ + [HELLO_MODULE]: { + custom_id: cartData.custom.id, + }, + }) + + return cartData.custom.id +}) + +// TODO delete Custom record +``` + +Using the `when-then` utility, you check if the cart has a linked `Custom` record and `custom_name` is `null` or an empty string. If so, you delete the linked `Custom` record and dismiss its links. + +Finally, replace the new `TODO` with the following: + +```ts title="src/workflows/update-custom-from-cart/index.ts" +const updated = when({ + input, + cartData, +}, (data) => data.cartData.custom && data.input.additional_data?.custom_name?.length > 0) +.then(() => { + const custom = updateCustomStep({ + id: cartData.custom.id, + custom_name: input.additional_data.custom_name, + }) + + return custom +}) + +return new WorkflowResponse({ + created, + updated, + deleted, +}) +``` + +Using the `when-then` utility, you check if the cart has a linked `Custom` record and `custom_name` is passed in the `additional_data`. If so, you update the linked `Custom` recod. + +You return in the workflow response the created, updated, and deleted `Custom` record. + +### Consume cartUpdated Workflow Hook + +You can now consume the `cartUpdated` and execute the workflow you created. + +Create the file `src/workflows/hooks/cart-updated.ts` with the following content: + +```ts title="src/workflows/hooks/cart-updated.ts" +import { updateCartWorkflow } from "@medusajs/medusa/core-flows" +import { + UpdateCustomFromCartStepInput, + updateCustomFromCartWorkflow, +} from "../update-custom-from-cart" + +updateCartWorkflow.hooks.cartUpdated( + async (hookData, { container }) => { + await updateCustomFromCartWorkflow(container) + .run({ + input: hookData as UpdateCustomFromCartStepInput, + }) + } +) +``` + +In the workflow hook handler, you execute the workflow, passing it the hook's input. + +### Test it Out + +To test it out, send a `POST` request to `/store/carts/:id` to update a cart, passing `custom_name` in `additional_data`: + +```bash +curl -X POST 'localhost:9000/store/carts/{cart_id}?fields=+custom.*' \ +-H 'x-publishable-api-key: {publishable_api_key}' \ +-H 'Content-Type: application/json' \ +--data '{ + "additional_data": { + "custom_name": "test 2" + } +}' +``` + +Make sure to replace `{cart_id}` with the cart's ID, and `{publishable_api_key}` with your publishable API key, which you can retrieve from the Medusa Admin. + +The request will return the cart's details with the updated `custom` linked record. diff --git a/www/apps/resources/app/commerce-modules/cart/links-to-other-modules/page.mdx b/www/apps/resources/app/commerce-modules/cart/links-to-other-modules/page.mdx new file mode 100644 index 0000000000..b6cf0c2054 --- /dev/null +++ b/www/apps/resources/app/commerce-modules/cart/links-to-other-modules/page.mdx @@ -0,0 +1,35 @@ +export const metadata = { + title: `Links between Cart Module and Other Modules`, +} + +# {metadata.title} + +This document showcases the module links defined between the Cart Module and other commerce modules. + +## Payment Module + +The Payment Module handles payment processing and management. + +Medusa defines a link between the `Cart` and `PaymentCollection` data models. A cart has a payment collection which holds all the authorized payment sessions and payments made related to the cart. + +![A diagram showcasing an example of how data models from the Cart and Payment modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711537849/Medusa%20Resources/cart-payment_ixziqm.jpg) + +--- + +## Promotion Module + +The Promotion Module provides discount features. + +Medusa defines a link between the `Cart` and `Promotion` data models. This indicates the promotions applied on a cart. + +![A diagram showcasing an example of how data models from the Cart and Promotion modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711538015/Medusa%20Resources/cart-promotion_kuh9vm.jpg) + +--- + +## Order Module + +The Order Module provides order-management features. + +Medusa defines a link between the `Cart` and `Order` data models. The cart is linked to the order created once the cart is completed. + +![A diagram showcasing an example of how data models from the Cart and Order modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1728375735/Medusa%20Resources/cart-order_ijwmfs.jpg) diff --git a/www/apps/resources/app/commerce-modules/cart/page.mdx b/www/apps/resources/app/commerce-modules/cart/page.mdx index 50fa1cb744..9effeea023 100644 --- a/www/apps/resources/app/commerce-modules/cart/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/page.mdx @@ -6,7 +6,7 @@ export const metadata = { # {metadata.title} -The Cart Module is the `@medusajs/medusa/cart` NPM package that provides cart-related features in your Medusa and Node.js applications. +The Cart Module provides cart-related features in your Medusa and Node.js applications. ## How to Use Cart Module's Service @@ -15,18 +15,33 @@ You can use the Cart Module's main service by resolving from the Medusa containe For example: + + +```ts title="src/workflows/hello-world/step1.ts" +import { createStep } from "@medusajs/framework/workflows-sdk" +import { Modules } from "@medusajs/framework/utils" + +const step1 = createStep("step-1", async (_, { container }) => { + const cartModuleService = container.resolve( + Modules.CART + ) + + const carts = await cartModuleService.listCarts() +}) +``` + + - ```ts title="src/api/store/custom/route.ts" - import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts title="src/api/store/custom/route.ts" +import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http" +import { Modules } from "@medusajs/framework/utils" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { - const cartModuleService: ICartModuleService = req.scope.resolve( + const cartModuleService = req.scope.resolve( Modules.CART ) @@ -39,35 +54,17 @@ export async function GET( - ```ts title="src/subscribers/custom-handler.ts" - import { SubscriberArgs } from "@medusajs/framework" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" +```ts title="src/subscribers/custom-handler.ts" +import { SubscriberArgs } from "@medusajs/framework" +import { Modules } from "@medusajs/framework/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { - const cartModuleService: ICartModuleService = container.resolve( + const cartModuleService = container.resolve( Modules.CART ) const carts = await cartModuleService.listCarts() } -``` - - - - - ```ts title="src/workflows/hello-world/step1.ts" - import { createStep } from "@medusajs/framework/workflows-sdk" - import { ICartModuleService } from "@medusajs/framework/types" - import { Modules } from "@medusajs/framework/utils" - -const step1 = createStep("step-1", async (_, { container }) => { - const cartModuleService: ICartModuleService = container.resolve( - Modules.CART - ) - - const carts = await cartModuleService.listCarts() -}) ``` @@ -121,7 +118,7 @@ const shippingAdjustments = A cart is scoped to a sales channel, region, and a customer. -When used with their respective modules and other commerce modules, you benefit from features like: +The Medusa application links the Cart Module to each of their respective modules, providing with features like: - Checking product availability in a sales channel. - Retrieving pricing per region. diff --git a/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx b/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx index f7bd4e5023..636c9474ff 100644 --- a/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx @@ -14,7 +14,7 @@ In this document, you’ll learn how a promotion is applied to a cart’s line i An adjustment line indicates a change to an item or a shipping method’s amount. It’s used to apply promotions or discounts on a cart. -The `LineItemAdjustment` data model represents changes on a line item, and the `ShippingMethodAdjustment` data model represents changes on a shipping method. +The [LineItemAdjustment](/references/cart/models/LineItemAdjustment) data model represents changes on a line item, and the [ShippingMethodAdjustment](/references/cart/models/ShippingMethodAdjustment) data model represents changes on a shipping method. ![A diagram showcasing the relations between other data models and adjustment line models](https://res.cloudinary.com/dza7lstvk/image/upload/v1711534248/Medusa%20Resources/cart-adjustments_k4sttb.jpg) @@ -24,7 +24,7 @@ The `amount` property of the adjustment line indicates the amount to be discount ## Discountable Option -The `LineItem` data model has an `is_discountable` property that indicates whether promotions can be applied to the line item. It’s enabled by default. +The [LineItem](/references/cart/models/LineItem) data model has an `is_discountable` property that indicates whether promotions can be applied to the line item. It’s enabled by default. When disabled, a promotion can’t be applied to a line item. In the context of the Promotion Module, the promotion isn’t applied to the line item even if it matches its rules. @@ -33,7 +33,7 @@ When disabled, a promotion can’t be applied to a line item. In the context of ## Promotion Actions -When using the Cart and Promotion modules together, use the [computeActions method of the Promotion Module’s main service](/references/promotion/computeActions). It retrieves the actions of line items and shipping methods. +When using the Cart and Promotion modules together, such as in the Medusa application, use the [computeActions method of the Promotion Module’s main service](/references/promotion/computeActions). It retrieves the actions of line items and shipping methods. @@ -41,6 +41,8 @@ Learn more about actions in the [Promotion Module’s documentation](../../promo +For example: + ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" import { ComputeActionAdjustmentLine, @@ -101,7 +103,7 @@ The `computeActions` method accepts the existing adjustments of line items and s Then, use the returned `addItemAdjustment` and `addShippingMethodAdjustment` actions to set the cart’s line item and the shipping method’s adjustments. -```ts collapsibleLines="1-9" expandButtonLabel="Show Imports" +```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" import { AddItemAdjustmentAction, AddShippingMethodAdjustment, diff --git a/www/apps/resources/app/commerce-modules/cart/relations-to-other-modules/page.mdx b/www/apps/resources/app/commerce-modules/cart/relations-to-other-modules/page.mdx deleted file mode 100644 index b6ba6bf4a0..0000000000 --- a/www/apps/resources/app/commerce-modules/cart/relations-to-other-modules/page.mdx +++ /dev/null @@ -1,53 +0,0 @@ -export const metadata = { - title: `Relations between Cart Module and Other Modules`, -} - -# {metadata.title} - -This document showcases the link modules defined between the Cart Module and other commerce modules. - -## Customer Module - -A cart is scoped to the customer using it. Medusa defines a link module that builds a relationship between the `Cart` and `Customer` data models. - -![A diagram showcasing an example of how data models from the Cart and Customer modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711537276/Medusa%20Resources/cart-customer_pnjvuw.jpg) - ---- - -## Payment Module - -The Payment Module allows you to associate payments with a cart. Medusa defines a link module that builds a relationship between the `Cart` and `PaymentCollection` data models. - -![A diagram showcasing an example of how data models from the Cart and Payment modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711537849/Medusa%20Resources/cart-payment_ixziqm.jpg) - ---- - -## Product Module - -A cart's line item is associated with a product and its variant. Medusa defines a link module that builds a relationship between the `Cart`, `Product`, and `ProductVariant` data models. - -![A diagram showcasing an example of how data models from the Cart and Product modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1716546229/Medusa%20Resources/cart-product_x82x9j.jpg) - ---- - -## Promotion Module - -A promotion can be applied on line items and shipping methods of a cart. Medusa defines a link module that builds a relationship between the `Cart`, `LineItemAdjustment`, and `Promotion` data models. - -![A diagram showcasing an example of how data models from the Cart and Promotion modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711538015/Medusa%20Resources/cart-promotion_kuh9vm.jpg) - ---- - -## Region Module - -A cart is scoped to a region. Medusa defines a link module that builds a relationship between the `Cart` and `Region` data models. - -![A diagram showcasing an example of how data models from the Cart and Region modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1716543714/Medusa%20Resources/customer-region_rtmymb.jpg) - ---- - -## Sales Channel Module - -A cart is scoped to a sales channel. Medusa defines a link module that builds a relationship between the `Cart` and `SalesChannel` data models. - -![A diagram showcasing an example of how data models from the Cart and Sales Channel modules are linked](https://res.cloudinary.com/dza7lstvk/image/upload/v1711538159/Medusa%20Resources/cart-sales-channel_n2oi0v.jpg) diff --git a/www/apps/resources/app/commerce-modules/cart/tax-lines/page.mdx b/www/apps/resources/app/commerce-modules/cart/tax-lines/page.mdx index 40bed45a41..eef445342c 100644 --- a/www/apps/resources/app/commerce-modules/cart/tax-lines/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/tax-lines/page.mdx @@ -16,7 +16,7 @@ A tax line indicates the tax rate of a line item or a shipping method. The [Line ## Tax Inclusivity -By default, the tax amount is calculated by taking the tax rate from the line item or shipping method’s amount, and then added to the item/method’s subtotal. +By default, the tax amount is calculated by taking the tax rate from the line item or shipping method’s amount, and then adding them to the item/method’s subtotal. However, line items and shipping methods have an `is_tax_inclusive` property that, when enabled, indicates that the item or method’s price already includes taxes. @@ -30,9 +30,11 @@ The following diagram is a simplified showcase of how a subtotal is calculated f ![A diagram showing an example of calculating the subtotal of a line item using its taxes](https://res.cloudinary.com/dza7lstvk/image/upload/v1711535295/Medusa%20Resources/cart-tax-inclusive_shpr3t.jpg) +For example, if a line item's amount is `5000`, the tax rate is `10`, and tax inclusivity is enabled, the tax amount is 10% of `5000`, which is `500`, making the unit price of the line item `4500`. + --- -## Retrieving Tax Lines +## Retrieve Tax Lines When using the Cart and Tax modules together, you can use the `getTaxLines` method of the Tax Module’s main service. It retrieves the tax lines for a cart’s line items and shipping methods. diff --git a/www/apps/resources/app/commerce-modules/page.mdx b/www/apps/resources/app/commerce-modules/page.mdx index 27c874ec18..2538553337 100644 --- a/www/apps/resources/app/commerce-modules/page.mdx +++ b/www/apps/resources/app/commerce-modules/page.mdx @@ -6,7 +6,13 @@ export const metadata = { # {metadata.title} -In this section of the documentation, you'll find guides and references related to Medusa's Commerce Modules. +In this section of the documentation, you'll find guides and references related to Medusa's commerce modules. + +A commerce module provides features for a commerce domain within its service. The Medusa application exposes these features in its API routes to clients. + +A commerce module also defines data models, representing tables in the database. Medusa's framework and tools allow you to extend these data models to add custom fields. + +## Commerce Modules List diff --git a/www/apps/resources/app/troubleshooting/dist-imports/page.mdx b/www/apps/resources/app/troubleshooting/dist-imports/page.mdx index 95b6395b65..dc6234394c 100644 --- a/www/apps/resources/app/troubleshooting/dist-imports/page.mdx +++ b/www/apps/resources/app/troubleshooting/dist-imports/page.mdx @@ -10,7 +10,7 @@ For example, this is not allowed: ```ts import { - AdminGetApiKeysParams + AdminGetApiKeysParams, } from "@medusajs/medusa/dist/api/admin/api-keys" // <-- Not allowed ``` @@ -31,6 +31,6 @@ So, this is allowed: ```ts import { - AdminGetApiKeysParams + AdminGetApiKeysParams, } from "@medusajs/medusa/api/admin/api-keys" // <-- Allowed ``` diff --git a/www/apps/resources/generated/edit-dates.mjs b/www/apps/resources/generated/edit-dates.mjs index 88257c07c4..daccbe7c8b 100644 --- a/www/apps/resources/generated/edit-dates.mjs +++ b/www/apps/resources/generated/edit-dates.mjs @@ -1,18 +1,17 @@ export const generatedEditDates = { - "app/commerce-modules/auth/auth-providers/emailpass/page.mdx": "2024-09-30T08:43:53.153Z", - "app/commerce-modules/auth/auth-providers/page.mdx": "2024-09-05T12:15:19.491Z", + "app/commerce-modules/auth/auth-providers/emailpass/page.mdx": "2024-10-08T07:35:59.167Z", + "app/commerce-modules/auth/auth-providers/page.mdx": "2024-10-08T07:27:21.859Z", "app/commerce-modules/auth/authentication-route/page.mdx": "2024-09-05T12:06:38.155Z", - "app/commerce-modules/auth/examples/page.mdx": "2024-09-30T08:43:53.154Z", - "app/commerce-modules/auth/module-options/page.mdx": "2024-09-30T08:43:53.156Z", - "app/commerce-modules/auth/page.mdx": "2024-09-30T08:43:53.156Z", + "app/commerce-modules/auth/examples/page.mdx": "2024-10-07T15:36:17.212Z", + "app/commerce-modules/auth/module-options/page.mdx": "2024-10-07T15:33:05.989Z", + "app/commerce-modules/auth/page.mdx": "2024-10-08T07:38:27.522Z", "app/commerce-modules/cart/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00", "app/commerce-modules/cart/_events/page.mdx": "2024-07-03T19:27:13+03:00", - "app/commerce-modules/cart/concepts/page.mdx": "2024-06-26T07:55:59+00:00", - "app/commerce-modules/cart/examples/page.mdx": "2024-09-30T08:43:53.157Z", - "app/commerce-modules/cart/promotions/page.mdx": "2024-09-30T08:43:53.158Z", - "app/commerce-modules/cart/relations-to-other-modules/page.mdx": "2024-05-29T11:08:06+00:00", - "app/commerce-modules/cart/tax-lines/page.mdx": "2024-06-26T07:55:59+00:00", - "app/commerce-modules/cart/page.mdx": "2024-09-30T08:43:53.157Z", + "app/commerce-modules/cart/concepts/page.mdx": "2024-10-08T07:49:03.737Z", + "app/commerce-modules/cart/examples/page.mdx": "2024-10-08T07:42:13.336Z", + "app/commerce-modules/cart/promotions/page.mdx": "2024-10-08T07:54:31.120Z", + "app/commerce-modules/cart/tax-lines/page.mdx": "2024-10-08T07:57:19.168Z", + "app/commerce-modules/cart/page.mdx": "2024-10-08T07:41:22.711Z", "app/commerce-modules/currency/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00", "app/commerce-modules/currency/_events/page.mdx": "2024-07-03T19:27:13+03:00", "app/commerce-modules/currency/examples/page.mdx": "2024-10-08T15:06:26.492Z", @@ -122,7 +121,7 @@ export const generatedEditDates = { "app/commerce-modules/user/module-options/page.mdx": "2024-09-30T08:43:53.171Z", "app/commerce-modules/user/user-creation-flows/page.mdx": "2024-06-26T07:55:59+00:00", "app/commerce-modules/user/page.mdx": "2024-09-30T08:43:53.172Z", - "app/commerce-modules/page.mdx": "2024-05-03T17:36:38+03:00", + "app/commerce-modules/page.mdx": "2024-10-07T13:55:08.014Z", "app/contribution-guidelines/_admin-translations/page.mdx": "2024-05-13T18:55:11+03:00", "app/contribution-guidelines/docs/page.mdx": "2024-05-13T18:55:11+03:00", "app/create-medusa-app/page.mdx": "2024-08-05T11:10:55+03:00", @@ -220,15 +219,14 @@ export const generatedEditDates = { "app/commerce-modules/auth/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00", "app/commerce-modules/auth/auth-flows/page.mdx": "2024-09-05T08:50:11.671Z", "app/commerce-modules/auth/_events/page.mdx": "2024-07-03T19:27:13+03:00", - "app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-09-05T08:11:28.936Z", - "app/commerce-modules/api-key/page.mdx": "2024-09-30T08:43:53.152Z", - "app/commerce-modules/auth/create-actor-type/page.mdx": "2024-09-30T08:43:53.154Z", + "app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-10-08T07:08:43.428Z", + "app/commerce-modules/api-key/page.mdx": "2024-10-07T13:57:33.042Z", + "app/commerce-modules/auth/create-actor-type/page.mdx": "2024-10-08T07:31:11.256Z", "app/architectural-modules/page.mdx": "2024-05-28T13:25:03+03:00", - "app/commerce-modules/api-key/relations-to-other-modules/page.mdx": "2024-05-29T11:08:06+00:00", "app/architectural-modules/workflow-engine/redis/page.mdx": "2024-09-30T08:43:53.152Z", - "app/commerce-modules/api-key/examples/page.mdx": "2024-09-30T08:43:53.152Z", + "app/commerce-modules/api-key/examples/page.mdx": "2024-10-07T13:58:49.457Z", "app/architectural-modules/notification/sendgrid/page.mdx": "2024-09-30T08:43:53.151Z", - "app/commerce-modules/api-key/concepts/page.mdx": "2024-06-26T07:55:59+00:00", + "app/commerce-modules/api-key/concepts/page.mdx": "2024-10-07T13:59:37.529Z", "app/architectural-modules/workflow-engine/page.mdx": "2024-05-28T13:25:03+03:00", "app/_events-reference/page.mdx": "2024-07-03T19:27:13+03:00", "app/architectural-modules/cache/page.mdx": "2024-05-28T13:25:03+03:00", @@ -906,8 +904,8 @@ export const generatedEditDates = { "references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimPreviewResponse/page.mdx": "2024-10-03T00:11:52.828Z", "references/types/HttpTypes/interfaces/types.HttpTypes.AdminOrderEditPreviewResponse/page.mdx": "2024-10-03T00:11:53.030Z", "references/types/interfaces/types.BaseClaim/page.mdx": "2024-10-03T00:11:52.699Z", - "app/commerce-modules/auth/auth-providers/github/page.mdx": "2024-09-30T08:43:53.153Z", - "app/commerce-modules/auth/auth-providers/google/page.mdx": "2024-09-30T08:43:53.153Z", + "app/commerce-modules/auth/auth-providers/github/page.mdx": "2024-10-08T07:37:27.882Z", + "app/commerce-modules/auth/auth-providers/google/page.mdx": "2024-10-08T07:37:06.517Z", "app/storefront-development/customers/third-party-login/page.mdx": "2024-09-11T09:58:51.801Z", "references/types/HttpTypes/types/types.HttpTypes.AdminWorkflowRunResponse/page.mdx": "2024-09-17T00:10:58.803Z", "references/types/HttpTypes/types/types.HttpTypes.BatchResponse/page.mdx": "2024-09-05T00:11:17.182Z", @@ -2220,6 +2218,11 @@ export const generatedEditDates = { "references/user/interfaces/user.IModuleService/page.mdx": "2024-10-03T00:12:20.657Z", "references/user/interfaces/user.MessageAggregatorFormat/page.mdx": "2024-10-03T00:12:20.662Z", "app/troubleshooting/dist-imports/page.mdx": "2024-10-03T09:19:37.639Z", + "app/commerce-modules/auth/reset-password/page.mdx": "2024-10-08T07:34:08.488Z", + "app/storefront-development/customers/reset-password/page.mdx": "2024-09-25T10:21:46.647Z", + "app/commerce-modules/api-key/links-to-other-modules/page.mdx": "2024-10-08T08:05:36.596Z", + "app/commerce-modules/cart/extend/page.mdx": "2024-10-08T11:22:22.523Z", + "app/commerce-modules/cart/links-to-other-modules/page.mdx": "2024-10-08T08:22:35.190Z", "app/commerce-modules/auth/reset-password/page.mdx": "2024-09-25T09:36:26.592Z", "app/storefront-development/customers/reset-password/page.mdx": "2024-09-25T10:21:46.647Z", "app/commerce-modules/customer/extend/page.mdx": "2024-10-08T14:18:55.407Z", diff --git a/www/apps/resources/generated/files-map.mjs b/www/apps/resources/generated/files-map.mjs index 32c6907195..47d9901a5c 100644 --- a/www/apps/resources/generated/files-map.mjs +++ b/www/apps/resources/generated/files-map.mjs @@ -88,12 +88,12 @@ export const filesMap = [ "pathname": "/commerce-modules/api-key/examples" }, { - "filePath": "/www/apps/resources/app/commerce-modules/api-key/page.mdx", - "pathname": "/commerce-modules/api-key" + "filePath": "/www/apps/resources/app/commerce-modules/api-key/links-to-other-modules/page.mdx", + "pathname": "/commerce-modules/api-key/links-to-other-modules" }, { - "filePath": "/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx", - "pathname": "/commerce-modules/api-key/relations-to-other-modules" + "filePath": "/www/apps/resources/app/commerce-modules/api-key/page.mdx", + "pathname": "/commerce-modules/api-key" }, { "filePath": "/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx", @@ -151,6 +151,14 @@ export const filesMap = [ "filePath": "/www/apps/resources/app/commerce-modules/cart/examples/page.mdx", "pathname": "/commerce-modules/cart/examples" }, + { + "filePath": "/www/apps/resources/app/commerce-modules/cart/extend/page.mdx", + "pathname": "/commerce-modules/cart/extend" + }, + { + "filePath": "/www/apps/resources/app/commerce-modules/cart/links-to-other-modules/page.mdx", + "pathname": "/commerce-modules/cart/links-to-other-modules" + }, { "filePath": "/www/apps/resources/app/commerce-modules/cart/page.mdx", "pathname": "/commerce-modules/cart" @@ -159,10 +167,6 @@ export const filesMap = [ "filePath": "/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx", "pathname": "/commerce-modules/cart/promotions" }, - { - "filePath": "/www/apps/resources/app/commerce-modules/cart/relations-to-other-modules/page.mdx", - "pathname": "/commerce-modules/cart/relations-to-other-modules" - }, { "filePath": "/www/apps/resources/app/commerce-modules/cart/tax-lines/page.mdx", "pathname": "/commerce-modules/cart/tax-lines" diff --git a/www/apps/resources/generated/sidebar.mjs b/www/apps/resources/generated/sidebar.mjs index fb93aaab9a..adbda2d6ff 100644 --- a/www/apps/resources/generated/sidebar.mjs +++ b/www/apps/resources/generated/sidebar.mjs @@ -56,8 +56,8 @@ export const generatedSidebar = [ "loaded": true, "isPathHref": true, "type": "link", - "path": "/commerce-modules/api-key/relations-to-other-modules", - "title": "Relation to Modules", + "path": "/commerce-modules/api-key/links-to-other-modules", + "title": "Link to Modules", "children": [] } ] @@ -538,6 +538,14 @@ export const generatedSidebar = [ "title": "Examples", "children": [] }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/commerce-modules/cart/extend", + "title": "Extend Module", + "children": [] + }, { "loaded": true, "isPathHref": true, @@ -572,8 +580,8 @@ export const generatedSidebar = [ "loaded": true, "isPathHref": true, "type": "link", - "path": "/commerce-modules/cart/relations-to-other-modules", - "title": "Relations to Other Modules", + "path": "/commerce-modules/cart/links-to-other-modules", + "title": "Links to Other Modules", "children": [] } ] diff --git a/www/apps/resources/next.config.mjs b/www/apps/resources/next.config.mjs index 96eda38506..1d62999cc4 100644 --- a/www/apps/resources/next.config.mjs +++ b/www/apps/resources/next.config.mjs @@ -44,6 +44,16 @@ const nextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH || "/v2/resources", async redirects() { return [ + { + source: "/commerce-modules/api-key/relations-to-other-modules", + destination: "/commerce-modules/api-key/links-to-other-modules", + permanent: true, + }, + { + source: "/commerce-modules/cart/relations-to-other-modules", + destination: "/commerce-modules/cart/links-to-other-modules", + permanent: true, + }, { source: "/commerce-modules/fulfillment/relations-to-other-modules", destination: "/commerce-modules/fulfillment/links-to-other-modules", diff --git a/www/apps/resources/sidebar.mjs b/www/apps/resources/sidebar.mjs index d60f37c04c..908fade290 100644 --- a/www/apps/resources/sidebar.mjs +++ b/www/apps/resources/sidebar.mjs @@ -39,8 +39,8 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, { type: "link", - path: "/commerce-modules/api-key/relations-to-other-modules", - title: "Relation to Modules", + path: "/commerce-modules/api-key/links-to-other-modules", + title: "Link to Modules", }, ], }, @@ -223,6 +223,11 @@ export const sidebar = sidebarAttachHrefCommonOptions([ path: "/commerce-modules/cart/examples", title: "Examples", }, + { + type: "link", + path: "/commerce-modules/cart/extend", + title: "Extend Module", + }, { type: "sub-category", title: "Concepts", @@ -244,8 +249,8 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, { type: "link", - path: "/commerce-modules/cart/relations-to-other-modules", - title: "Relations to Other Modules", + path: "/commerce-modules/cart/links-to-other-modules", + title: "Links to Other Modules", }, ], },