docs: fix code block titles (#5733)

* docs: fix code block titles

* remove console

* fix build error
This commit is contained in:
Shahed Nasser
2023-11-27 16:08:10 +00:00
committed by GitHub
parent de8f748674
commit 547b16ead5
110 changed files with 483 additions and 456 deletions
+1 -1
View File
@@ -35,7 +35,7 @@
"openapi-sampler": "^1.3.1",
"openapi-types": "^12.1.3",
"postcss": "8.4.27",
"prism-react-renderer": "^2.0.6",
"prism-react-renderer": "^2.3.0",
"react": "latest",
"react-dom": "latest",
"react-instantsearch": "^7.0.1",
+3 -3
View File
@@ -12,7 +12,7 @@ In this document, you'll learn about the different ways you can configure the ad
The `build` command in the admin CLI allows you to manually build the admin dashboard. If you intend to use it, you should typically add it to the `package.json` of the Medusa backend:
```json title=package.json
```json title="package.json"
{
"scripts": {
// other scripts...
@@ -29,7 +29,7 @@ You can add the following option to the `medusa-admin build` command:
The `develop` command in the admin CLI allows you to run the admin dashboard in development separately from the Medusa backend. If you intend to use it, you should typically add it to the `package.json` of the Medusa backend:
```json title=package.json
```json title="package.json"
{
"scripts": {
// other scripts...
@@ -84,7 +84,7 @@ This is an advanced feature and requires knowledge of configuring webpack. If co
For example:
```js title=src/admin/webpack.config.js
```js title="src/admin/webpack.config.js"
import { withCustomWebpackConfig } from "@medusajs/admin"
export default withCustomWebpackConfig((config, webpack) => {
+20 -20
View File
@@ -62,7 +62,7 @@ Each of the collapsible elements below hold the path to the file that you should
<Details>
<Summary>src/admin/types/icon-type.ts</Summary>
```tsx title=src/admin/types/icon-type.ts
```tsx title="src/admin/types/icon-type.ts"
import React from "react"
type IconProps = {
@@ -80,7 +80,7 @@ Each of the collapsible elements below hold the path to the file that you should
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/shared/icons/get-started.tsx
```tsx title="src/admin/components/shared/icons/get-started.tsx"
import React from "react"
import IconProps from "../../../types/icon-type"
@@ -115,7 +115,7 @@ Each of the collapsible elements below hold the path to the file that you should
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/shared/icons/dollar-sign-icon.tsx
```tsx title="src/admin/components/shared/icons/dollar-sign-icon.tsx"
import React from "react"
import IconProps from "../../../types/icon-type"
@@ -162,7 +162,7 @@ Each of the collapsible elements below hold the path to the file that you should
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/shared/accordion.tsx
```tsx title="src/admin/components/shared/accordion.tsx"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import React from "react"
import { CheckCircleSolid, CircleMiniSolid } from "@medusajs/icons"
@@ -295,7 +295,7 @@ Each of the collapsible elements below hold the path to the file that you should
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/shared/card.tsx
```tsx title="src/admin/components/shared/card.tsx"
import { Text, clx } from "@medusajs/ui"
type CardProps = {
@@ -348,7 +348,7 @@ An [entity](../development/entities/overview.mdx) represents a table in the data
To create the entity, create the file `src/models/onboarding.ts` with the following content:
```ts title=src/models/onboarding.ts
```ts title="src/models/onboarding.ts"
import { BaseEntity } from "@medusajs/medusa"
import { Column, Entity } from "typeorm"
@@ -367,7 +367,7 @@ export class OnboardingState extends BaseEntity {
Then, create the file `src/repositories/onboarding.ts` that holds the repository of the entity with the following content:
```ts title=src/repositories/onboarding.ts
```ts title="src/repositories/onboarding.ts"
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
@@ -450,7 +450,7 @@ Start by creating the file `src/types/onboarding.ts` with the following content:
<!-- eslint-disable @typescript-eslint/no-empty-interface -->
```ts title=src/types/onboarding.ts
```ts title="src/types/onboarding.ts"
import { OnboardingState } from "../models/onboarding"
export type UpdateOnboardingStateInput = {
@@ -472,7 +472,7 @@ Then, create the file `src/services/onboarding.ts` with the following content:
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/onboarding.ts
```ts title="src/services/onboarding.ts"
import { TransactionBaseService } from "@medusajs/medusa"
import OnboardingRepository from "../repositories/onboarding"
import { OnboardingState } from "../models/onboarding"
@@ -540,7 +540,7 @@ The last part of this step is to create the [API Routes](../development/api-rout
To add these API Routes, create the file `src/api/admin/onboarding/route.ts` with the following content:
```ts title=src/api/admin/onboarding/route.ts
```ts title="src/api/admin/onboarding/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -597,7 +597,7 @@ Create the file `src/admin/widgets/onboarding-flow/onboarding-flow.tsx` with the
<!-- eslint-disable @typescript-eslint/ban-types -->
```tsx title=src/admin/widgets/onboarding-flow/onboarding-flow.tsx
```tsx title="src/admin/widgets/onboarding-flow/onboarding-flow.tsx"
import { OrderDetailsWidgetProps, ProductDetailsWidgetProps, WidgetConfig, WidgetProps } from "@medusajs/admin"
import { useAdminCustomPost, useAdminCustomQuery, useMedusa } from "medusa-react"
import React, { useEffect, useState, useMemo, useCallback } from "react"
@@ -1059,7 +1059,7 @@ const OnboardingFlow = (props: OnboardingWidgetProps) => {
const isCurrent = currentStep === step.id
return (
<Accordion.Item
title={step.title}
title="{step.title}"
value={step.id}
headingSize="medium"
active={isCurrent}
@@ -1135,7 +1135,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/default/products/products-list.tsx
```tsx title="src/admin/components/onboarding-flow/default/products/products-list.tsx"
import React, { useMemo } from "react"
import {
useAdminCreateProduct,
@@ -1221,7 +1221,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/default/products/product-detail.tsx
```tsx title="src/admin/components/onboarding-flow/default/products/product-detail.tsx"
import React, { useEffect, useMemo } from "react"
import {
useAdminPublishableApiKeys,
@@ -1325,7 +1325,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/default/orders/orders-list.tsx
```tsx title="src/admin/components/onboarding-flow/default/orders/orders-list.tsx"
import React from "react"
import {
useAdminProduct,
@@ -1420,7 +1420,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/default/orders/order-detail.tsx
```tsx title="src/admin/components/onboarding-flow/default/orders/order-detail.tsx"
import React from "react"
import {
ComputerDesktopSolid,
@@ -1571,7 +1571,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/nextjs/products/products-list.tsx
```tsx title="src/admin/components/onboarding-flow/nextjs/products/products-list.tsx"
import React from "react"
import {
useAdminCreateProduct,
@@ -1669,7 +1669,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/nextjs/products/product-detail.tsx
```tsx title="src/admin/components/onboarding-flow/nextjs/products/product-detail.tsx"
import { useAdminProduct } from "medusa-react"
import { StepContentProps } from "../../../../widgets/onboarding-flow/onboarding-flow"
import { Button, Text } from "@medusajs/ui"
@@ -1737,7 +1737,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/nextjs/orders/orders-list.tsx
```tsx title="src/admin/components/onboarding-flow/nextjs/orders/orders-list.tsx"
import React from "react"
import {
useAdminProduct,
@@ -1817,7 +1817,7 @@ Notice that as there are two types of flows, you'll be creating the components f
<!-- eslint-disable max-len -->
```tsx title=src/admin/components/onboarding-flow/nextjs/orders/order-detail.tsx
```tsx title="src/admin/components/onboarding-flow/nextjs/orders/order-detail.tsx"
import React from "react"
import { CurrencyDollarSolid, NextJs, SquaresPlusSolid } from "@medusajs/icons"
import { IconBadge, Heading, Text } from "@medusajs/ui"
+1 -1
View File
@@ -56,7 +56,7 @@ npm install @medusajs/admin
In `medusa-config.js`, add the admin plugin into the array of `plugins`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
+9 -9
View File
@@ -40,7 +40,7 @@ These changes may already be available in your Medusa project. They're included
First, update your `tsconfig.json` with the following configurations:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"target": "es2019",
@@ -81,7 +81,7 @@ The addition of `"jsx": "react-jsx"` specified how should TypeScript transform J
Next, create the file `tsconfig.server.json` with the following content:
```json title=tsconfig.server.json
```json title="tsconfig.server.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -96,7 +96,7 @@ This is the configuration that will be used to transpile your custom backend cod
Finally, create the file `tsconfig.admin.json` with the following content:
```json title=tsconfig.admin.json
```json title="tsconfig.admin.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -135,7 +135,7 @@ For an admin route to be valid, it must default export a React component. There
For example, you can create the file `src/admin/routes/custom/page.tsx` with the following content:
```tsx title=src/admin/routes/custom/page.tsx
```tsx title="src/admin/routes/custom/page.tsx"
const CustomPage = () => {
return (
<div>
@@ -217,7 +217,7 @@ The object has one property `link`, which is an object having the following prop
For example, you can change the content of the previous route you created to export a config object:
```tsx title=src/admin/routes/custom/page.tsx
```tsx title="src/admin/routes/custom/page.tsx"
import { RouteConfig } from "@medusajs/admin"
import { CustomIcon } from "../../icons/custom"
@@ -261,7 +261,7 @@ If you're installing it in a plugin with admin customizations, make sure to incl
For example:
```tsx title=src/admin/routes/custom/[id]/page.tsx
```tsx title="src/admin/routes/custom/[id]/page.tsx"
import { useParams } from "react-router-dom"
const CustomPage = () => {
@@ -285,7 +285,7 @@ If you want to use routing functionalities such as linking to another page or na
For example, to add a link to another page:
```tsx title=src/admin/routes/custom/page.tsx
```tsx title="src/admin/routes/custom/page.tsx"
import { Link } from "react-router-dom"
const CustomPage = () => {
@@ -314,7 +314,7 @@ For example, to customize your custom route:
<!-- eslint-disable max-len -->
```tsx title=src/admin/routes/custom/page.tsx
```tsx title="src/admin/routes/custom/page.tsx"
const CustomPage = () => {
return (
<div
@@ -341,7 +341,7 @@ Make sure to also install the Medusa React package first if youre intending t
For example, you can retrieve available products and display them in your route:
```tsx title=src/admin/routes/custom/page.tsx
```tsx title="src/admin/routes/custom/page.tsx"
import { useAdminProducts } from "medusa-react"
const CustomPage = () => {
+8 -8
View File
@@ -36,7 +36,7 @@ These changes may already be available in your Medusa project. They're included
First, update your `tsconfig.json` with the following configurations:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"target": "es2019",
@@ -77,7 +77,7 @@ The addition of `"jsx": "react-jsx"` specified how should TypeScript transform J
Next, create the file `tsconfig.server.json` with the following content:
```json title=tsconfig.server.json
```json title="tsconfig.server.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -92,7 +92,7 @@ This is the configuration that will be used to transpile your custom backend cod
Finally, create the file `tsconfig.admin.json` with the following content:
```json title=tsconfig.admin.json
```json title="tsconfig.admin.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -131,7 +131,7 @@ For a setting page to be valid, it must default export a React component. There
For example, you can create the file `src/admin/settings/custom/page.tsx` with the following content:
```tsx title=src/admin/settings/custom/page.tsx
```tsx title="src/admin/settings/custom/page.tsx"
import type { SettingConfig } from "@medusajs/admin"
import { CustomIcon } from "../../icons/custom"
@@ -184,7 +184,7 @@ Every route receives props of the type `RouteProps`, which includes the `notify`
For example:
```tsx title=src/admin/settings/custom/page.tsx
```tsx title="src/admin/settings/custom/page.tsx"
import type { SettingConfig } from "@medusajs/admin"
import type { SettingProps } from "@medusajs/admin"
@@ -226,7 +226,7 @@ For example, to customize the style of your custom setting page:
<!-- eslint-disable max-len -->
```tsx title=src/admin/settings/custom/page.tsx
```tsx title="src/admin/settings/custom/page.tsx"
import type { SettingConfig } from "@medusajs/admin"
const CustomSettingPage = () => {
@@ -269,7 +269,7 @@ If you're installing it in a plugin with admin customizations, make sure to incl
For example, to add a link to another page:
```tsx title=src/admin/settings/custom/page.tsx
```tsx title="src/admin/settings/custom/page.tsx"
import type { SettingConfig } from "@medusajs/admin"
import { Link } from "react-router-dom"
@@ -310,7 +310,7 @@ Make sure to also install the Medusa React package first if youre intending t
For example, you can retrieve available products and display them in your route:
```tsx title=src/admin/settings/custom/page.tsx
```tsx title="src/admin/settings/custom/page.tsx"
import type { SettingConfig } from "@medusajs/admin"
import { useAdminProducts } from "medusa-react"
+9 -9
View File
@@ -956,7 +956,7 @@ These changes may already be available in your Medusa project. They're included
First, update your `tsconfig.json` with the following configurations:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"target": "es2019",
@@ -997,7 +997,7 @@ The addition of `"jsx": "react-jsx"` specified how should TypeScript transform J
Next, create the file `tsconfig.server.json` with the following content:
```json title=tsconfig.server.json
```json title="tsconfig.server.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -1012,7 +1012,7 @@ This is the configuration that will be used to transpile your custom backend cod
Finally, create the file `tsconfig.admin.json` with the following content:
```json title=tsconfig.admin.json
```json title="tsconfig.admin.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -1029,7 +1029,7 @@ This is the configuration that will be used when transpiling your admin code.
You can optionally update the following scripts in `package.json` to make your development process easier:
```json title=package.json
```json title="package.json"
{
// ...
"scripts": {
@@ -1060,7 +1060,7 @@ To create a new admin widget, start by creating the folder `src/admin/widgets`.
Then, create the file `src/admin/widgets/product-widget.tsx` with the following content:
```tsx title=src/admin/widgets/product-widget.tsx
```tsx title="src/admin/widgets/product-widget.tsx"
import type { WidgetConfig } from "@medusajs/admin"
const ProductWidget = () => {
@@ -1111,7 +1111,7 @@ For example, you can modify the widget you created to show the title of the prod
<!-- eslint-disable max-len -->
```tsx title=src/admin/widgets/product-widget.tsx
```tsx title="src/admin/widgets/product-widget.tsx"
import type {
WidgetConfig,
ProductDetailsWidgetProps,
@@ -1151,7 +1151,7 @@ For example, you can update the widget you created earlier to use Tailwind CSS c
<!-- eslint-disable max-len -->
```tsx title=src/admin/widgets/product-widget.tsx
```tsx title="src/admin/widgets/product-widget.tsx"
import type {
WidgetConfig,
} from "@medusajs/admin"
@@ -1194,7 +1194,7 @@ For example:
<!-- eslint-disable max-len -->
```tsx title=src/admin/widgets/product-widget.tsx
```tsx title="src/admin/widgets/product-widget.tsx"
import type { WidgetConfig } from "@medusajs/admin"
import { Link } from "react-router-dom"
@@ -1235,7 +1235,7 @@ For example, you can modify the widget you created to retrieve the tags of a pro
<!-- eslint-disable max-len -->
```tsx title=src/admin/widgets/product-widget.tsx
```tsx title="src/admin/widgets/product-widget.tsx"
import type { ProductDetailsWidgetProps, WidgetConfig } from "@medusajs/admin"
import { useAdminProductTags } from "medusa-react"
@@ -43,7 +43,7 @@ Where `<LANGUAGE>` is your language name. For example, `feat/translate-da`.
7\. In `packages/admin-ui/ui/src/i18n/index.ts`, add the new language to the `supportedLanguages` array as an object. The object accepts two properties: `locale` for the ISO 2 character code, and `name` for the name of the language. The name of the language should be the translated name, not the English name. For example:
```ts title=packages/admin-ui/ui/src/i18n/index.ts
```ts title="packages/admin-ui/ui/src/i18n/index.ts"
export const supportedLanguages = [
// other languages...
{
+10 -10
View File
@@ -120,7 +120,7 @@ To add an icon to the sidebar item, start by checking if the icon is already exp
For example:
```tsx title=www/docs/src/theme/Icon/Bolt/index.tsx
```tsx title="www/docs/src/theme/Icon/Bolt/index.tsx"
import React from "react"
import { IconProps } from "@medusajs/icons/dist/types"
@@ -148,7 +148,7 @@ Make sure to set the `stroke` or `fill` of the icon to `currentColor` as shown i
If you added a new icon, add it in the exported object in the file `www/apps/docs/src/theme/Icon/index.ts`, where the property is the kebab-case version of the icon's name, and the value being the component you created. Make sure to add it in the correct alphabetical position as well. For example:
```ts title=www/docs/src/theme/Icon/index.ts
```ts title="www/docs/src/theme/Icon/index.ts"
import IconBolt from "./Bolt"
import IconBoltSolid from "./BoltSolid"
// other imports
@@ -163,7 +163,7 @@ export default {
Finally, you can add the icon to the sidebar item by adding a `sidebar_icon` property to the `customProps` property and setting its value to the kebab-cased version of the icon's name. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
homepage: [
@@ -184,7 +184,7 @@ There are different sidebar item types used in the documentation:
- Homepage Items: If a sidebar item is shown under the `homepage` sidebar, you should set the `className` property of the item to `homepage-sidebar-item`. You can use this with other sidebar item types. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
homepage: [
@@ -200,7 +200,7 @@ There are different sidebar item types used in the documentation:
- Sidebar Title: This item is used as a title to the sidebar, typically added at the top of the sidebar. You typically would also use an icon with it. To use this item, add a `sidebar_is_title` property to the `customProps` object of the item with its value being `true`. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
modules: [
@@ -221,7 +221,7 @@ There are different sidebar item types used in the documentation:
- Back Item: This item is used to show a back button, typically at the top of the sidebar. To use this item, add the `sidebar_is_back_link` property to the `customProps` object of the item, with its value set to true. Also, add the `sidebar_icon` property to the `customProps` object with its value set to `back-arrow`. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
core: [
@@ -242,7 +242,7 @@ There are different sidebar item types used in the documentation:
- Group Divider Item: This item is used if a sidebar item does not link to any document and is only used to separate between sidebar sections. The item must be of type `html`, and its `value` property holds the text that should be shown in the divider. You must also add in the `customProps` object of the item the property `sidebar_is_group_divider` with its value being `true`. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
homepage: [
@@ -262,7 +262,7 @@ There are different sidebar item types used in the documentation:
- Group Headline Item: This item is used if a sidebar item does not link to any document and is only used to indicate the beginning of a new section or group in the sidebar. To use this item, set the `type` of the item to `category`, and add the `sidebar_is_group_headline` property to the `customProps` object of the item, with its value set to `true`. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
modules: [
@@ -285,7 +285,7 @@ There are different sidebar item types used in the documentation:
- Soon Item: This item is used to indicate that a certain guide will be added soon, but it does not actually link to any document. To use this item, set the `type` of the item to `link`, its `href` property to `#`, and add to the `customProps` object the property `sidebar_is_soon` with its value set to `true`. For example:
```js title=www/docs/sidebars.js
```js title="www/docs/sidebars.js"
module.exports = {
// other sidebars
modules: [
@@ -392,7 +392,7 @@ For example:
To add a title to a code block without tabs:
~~~md
```js title=src/index.ts
```js title="src/index.ts"
console.log("hello")
```
~~~
@@ -66,7 +66,7 @@ const DATABASE_URL =
In addition, you must add to `projectConfig` in the exported object a new property `database_extra`:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
// ...
@@ -77,7 +77,7 @@ module.exports = {
Also, if you're planning on using scheduled jobs, you need to set the `redis_url` configurations:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
// ...
@@ -25,7 +25,7 @@ If your hosting provider supports that, create a GitHub repository and push your
Make sure the `start` script in your `package.json` runs migrations, the `build` command, and the `medusa start` command:
```json title=package.json
```json title="package.json"
"start": "npm run build && medusa migrations run && medusa start"
```
@@ -35,7 +35,7 @@ Make sure the `start` script in your `package.json` runs migrations, the `build`
In production, its recommended to set the [database_extra option](../../development/backend/configurations.md#database_extra) in `medusa-config.js` to disable the `ssl.rejectUnauthorized` option:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
module.exports = {
projectConfig: {
// ...
@@ -48,7 +48,7 @@ You can learn more about Middlewares and their capabilities in [Expresss docu
Here's an example of a middleware:
```ts title=src/api/middlewares/custom-middleware.ts
```ts title="src/api/middlewares/custom-middleware.ts"
export function customMiddleware(req, res, next) {
// TODO perform an action
@@ -66,7 +66,7 @@ The examples used here don't apply Cross-Origin Resource Origin (CORS) options f
:::
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { Router } from "express"
import {
customMiddleware,
@@ -118,7 +118,7 @@ If you want to register a logged-in user and access it in your resources, you ca
To register a new resource in the dependency container, use the `req.scope.register` method:
```ts title=src/api/middlewares/custom-middleware.ts
```ts title="src/api/middlewares/custom-middleware.ts"
export function customMiddleware(req, res, next) {
// TODO perform an action
@@ -136,7 +136,7 @@ You can then load this new resource within other resources. For example, to load
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/custom-service.ts
```ts title="src/services/custom-service.ts"
import { TransactionBaseService } from "@medusajs/medusa"
class CustomService extends TransactionBaseService {
@@ -18,7 +18,7 @@ v1.17.2 of `@medusajs/medusa` introduced a new approach to creating middlewares
## Basic Implementation
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type { MiddlewaresConfig } from "@medusajs/medusa"
import type {
MedusaNextFunction,
@@ -99,7 +99,7 @@ The `resolve`'s value is a function that returns the resource to be registered i
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type { MiddlewaresConfig } from "@medusajs/medusa"
import type {
MedusaNextFunction,
@@ -134,7 +134,7 @@ You can then load this new resource within other resources. For example, to load
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/custom-service.ts
```ts title="src/services/custom-service.ts"
import { TransactionBaseService } from "@medusajs/medusa"
class CustomService extends TransactionBaseService {
@@ -19,7 +19,7 @@ Following v1.17.2 of `@medusajs/medusa`, it's highly recommended to use the [API
To create a new endpoint, start by creating a new file in `src/api` called `index.ts`. At its basic format, `index.ts` should look something like this:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { Router } from "express"
export default (rootDirectory, options) => {
@@ -62,7 +62,7 @@ Instead of returning an Express router in the function, you can return an array
For example:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { Router } from "express"
export default (rootDirectory, options) => {
@@ -199,7 +199,7 @@ If you want to accept request body parameters, you need to pass express middlewa
For example:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import bodyParser from "body-parser"
import express, { Router } from "express"
@@ -356,7 +356,7 @@ The function returns an object with the following properties:
Here's an example of retrieving the configurations within an endpoint using `getConfigFile`:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { Router } from "express"
import { ConfigModule } from "@medusajs/medusa"
import { getConfigFile } from "medusa-core-utils"
@@ -382,7 +382,7 @@ Notice that `getConfigFile` is a generic function. So, if you're using TypeScrip
If you're accessing custom configurations, you'll need to create a new type that defines these configurations. For example:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { Router } from "express"
import { ConfigModule } from "@medusajs/medusa"
import { getConfigFile } from "medusa-core-utils"
@@ -426,7 +426,7 @@ Code snippets are taken from the [full example available at the end of this docu
To handle errors using Medusa's middlewares, first, import the `errorHandler` middleware from `@medusajs/medusa` and apply it on your routers. Make sure it's applied after all other middlewares and routes:
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import express, { Router } from "express"
import adminRoutes from "./admin"
import storeRoutes from "./store"
@@ -449,7 +449,7 @@ export default (rootDirectory, options) => {
Then, wrap the function handler of every route with the `wrapHandler` middleware imported from `@medusajs/medusa`. For example:
```ts title=src/api/admin.ts
```ts title="src/api/admin.ts"
import { wrapHandler } from "@medusajs/medusa"
// ...
@@ -477,7 +477,7 @@ Alternatively, you can define the endpoints in different files, and import and u
<!-- eslint-disable @typescript-eslint/no-var-requires -->
```ts title=src/api/admin.ts
```ts title="src/api/admin.ts"
import { wrapHandler } from "@medusajs/medusa"
// ...
@@ -17,7 +17,7 @@ v1.17.2 of `@medusajs/medusa` introduced API Routes to replace Express endpoints
## Basic Implementation
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -91,7 +91,7 @@ You can access a path parameter's value in method handlers using the `MedusaRequ
For example:
```ts title=src/api/store/custom/[id]/route.ts
```ts title="src/api/store/custom/[id]/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -119,7 +119,7 @@ The `cors` middleware, which enables Cross-Origin Resource Sharing (CORS), is au
To add CORS configurations to custom API routes under other path prefixes, or override the CORS configurations added by default, define a [middleware](./add-middleware.mdx) on your API routes and pass it the `cors` middleware. For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type {
MiddlewaresConfig,
} from "@medusajs/medusa"
@@ -146,7 +146,7 @@ To disable the `cors` middleware for an API Route, export a `CORS` variable in t
For example:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -174,7 +174,7 @@ Each of the `body`'s keys are a name of the request body parameters, and its val
For example:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -194,7 +194,7 @@ If you want to parse other content types, such as `application/x-www-form-urlenc
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type {
MiddlewaresConfig,
} from "@medusajs/medusa"
@@ -224,7 +224,7 @@ You can opt out of the default body parser by setting the `bodyParser` property
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
import { raw } from "body-parser"
@@ -243,7 +243,7 @@ You can also disable the default `json` body parser for specific HTTP methods us
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
import { raw } from "body-parser"
@@ -269,7 +269,7 @@ If you expect the request body of an API Route to be larger than the default, yo
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
@@ -294,7 +294,7 @@ By default, API routes prefixed by `/store` don't require customer authenticatio
For example:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import { CustomerService } from "@medusajs/medusa"
import type {
MedusaRequest,
@@ -327,7 +327,7 @@ API Routes prefixed by `/store/me`, on the other hand, require customer authenti
If you want to disable authentication requirement on your custom API Route prefixed with `/store/me`, export an `AUTHENTICATE` variable in the route file with its value set to `false`. For example:
```ts title=src/api/store/me/custom/route.ts
```ts title="src/api/store/me/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -357,7 +357,7 @@ By default, all API Routes prefixed by `/admin` require admin user authenticatio
For example:
```ts title=src/api/admin/custom/route.ts
```ts title="src/api/admin/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -384,7 +384,7 @@ To disable authentication requirement on an admin API Route, export an `AUTHENTI
For example:
```ts title=src/api/admin/custom/route.ts
```ts title="src/api/admin/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -418,7 +418,7 @@ To protect API routes that aren't prefixed with `/store` or `/admin`, you can us
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import {
authenticate,
requireCustomerAuthentication,
@@ -447,7 +447,7 @@ You can access the configurations exported in `medusa-config.js`, including your
For example:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -562,7 +562,7 @@ To override the default error handler, pass the `errorHandler` property to the [
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
@@ -578,7 +578,7 @@ To disable the default error handler, set the `errorHandler` property of the [ex
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import { MiddlewaresConfig } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
@@ -592,7 +592,7 @@ To ensure that errors are still returned in the response when the default error
For example:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import {
MedusaRequest,
MedusaResponse,
@@ -624,7 +624,7 @@ Posts are represented by a custom entity not covered in this guide. You can refe
:::
```ts title=src/api/store/posts/route.ts
```ts title="src/api/store/posts/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -659,7 +659,7 @@ Notice that to retrieve an instance of the repository, you need to retrieve firs
:::
```ts title=src/api/store/posts/route.ts
```ts title="src/api/store/posts/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -22,7 +22,7 @@ Learn more about [middlewares in its guide](./add-middleware.mdx).
Create the file `src/api/middlewares.ts` with the following content:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type {
MiddlewaresConfig,
User,
@@ -40,7 +40,7 @@ In the file you created, which in this case is `src/api/index.ts`, add the follo
<!-- eslint-disable max-len -->
```ts title=src/api/index.ts
```ts title="src/api/index.ts"
import { registerOverriddenValidators } from "@medusajs/medusa"
import {
AdminPostProductsReq as MedusaAdminPostProductsReq,
@@ -27,7 +27,7 @@ The configurations for your Medusa backend are in `medusa-config.js` located in
For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig,
plugins,
@@ -76,7 +76,7 @@ ADMIN_CORS=/http:\/\/*/
Typically, the value of these configurations would be set in an environment variable and referenced in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
admin_cors: process.env.ADMIN_CORS,
@@ -89,7 +89,7 @@ module.exports = {
If youre adding the value directly within `medusa-config.js`, make sure to add an extra escaping `/` for every backslash in the pattern. For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
admin_cors: "/http:\\/\\/localhost:700\\d+$/",
@@ -108,7 +108,7 @@ In a development environment, if this option is not set the default secret is `s
Typically, the value of this configuration would be set in an environment variable and referenced in `medusa-config.js`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
cookie_secret: process.env.COOKIE_SECRET,
@@ -131,7 +131,7 @@ Its value is an object that has the following properties:
If you enable HTTP compression and you want to disable it for specific API Routes, you can pass in the request header `"x-no-compression": true`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
http_compression: {
@@ -154,7 +154,7 @@ In a development environment, if this option is not set the default secret is `s
Typically, the value of this configuration would be set in an environment variable and referenced in `medusa-config.js`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
jwt_secret: process.env.JWT_SECRET,
@@ -170,7 +170,7 @@ The name of the database to connect to. If provided in `database_url`, then it
Make sure to create the PostgreSQL database before using it. You can check how to create a database in [PostgreSQL's documentation](https://www.postgresql.org/docs/current/sql-createdatabase.html).
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_database: "medusa-store",
@@ -186,7 +186,7 @@ An object that includes additional configurations to pass to the database connec
This is useful for production databases, which can be supported by setting the `rejectUnauthorized` attribute of `ssl` object to `false`. During development, its recommended not to pass this option.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_extra:
@@ -207,7 +207,7 @@ This configuration specifies what messages to log. Its value can be one of the f
- The string value `all` that indicates all types of messages should be logged.
- An array of log-level strings to indicate which type of messages to show in the logs. The strings can be `query`, `schema`, `error`, `warn`, `info`, `log`, or `migration`. Refer to [Typeorms documentation](https://typeorm.io/logging#logging-options) for more details on what each of these values means.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_logging: [
@@ -223,7 +223,7 @@ module.exports = {
A string indicating the database schema to connect to. This is not necessary to provide if youre using the default schema, which is `public`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_schema: "custom",
@@ -237,7 +237,7 @@ module.exports = {
A string indicating the type of database to connect to. At the moment, only `postgres` is accepted, which is also the default value.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_type: "postgres",
@@ -273,7 +273,7 @@ DATABASE_URL=postgres://postgres@localhost/medusa-store
You can learn more about the connection URL format in [PostgreSQLs documentation](https://www.postgresql.org/docs/current/libpq-connect.html).
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
database_url: process.env.DATABASE_URL,
@@ -303,7 +303,7 @@ For a local Redis installation, the connection URL should be `redis://localhost:
Typically, the value would be added as an environment variable and referenced in `medusa-config.js`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
redis_url: process.env.REDIS_URL,
@@ -317,7 +317,7 @@ module.exports = {
The prefix set on all keys stored in Redis. The default value is `sess:`. If this configuration option is provided, it is prepended to `sess:`.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
redis_prefix: "medusa:",
@@ -331,7 +331,7 @@ module.exports = {
An object of options to pass ioredis. You can refer to [iorediss RedisOptions documentation](https://redis.github.io/ioredis/index.html#RedisOptions) for the list of available options.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
redis_options: {
@@ -354,7 +354,7 @@ An object of options to pass to `express-session`. The object can have the follo
- `secret`: A string that indicates the secret to sign the session ID cookie. By default, the value of [cookie_secret](#cookie_secret) will be used. Refer to [express-sessions documentation](https://www.npmjs.com/package/express-session#secret) for details.
- `ttl`: A number is used when calculating the `Expires` `Set-Cookie` attribute of cookies. By default, itll be `10 * 60 * 60 * 1000`. Refer to [express-sessions documentation](https://www.npmjs.com/package/express-session#cookiemaxage) for details.
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
projectConfig: {
session_options: {
@@ -383,7 +383,7 @@ The items in the array can either be:
For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
plugins: [
`medusa-my-plugin-1`,
@@ -422,7 +422,7 @@ The keys of the `modules` configuration object refer to the type of module. Its
For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
modules: {
eventBus: {
@@ -457,7 +457,7 @@ You can find available feature flags and their key name [here](https://github.co
For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
featureFlags: {
product_categories: true,
@@ -46,7 +46,7 @@ Batch job strategies must extend the abstract class `AbstractBatchJobStrategy` a
Add the following content to the file you created:
```ts title=src/strategies/publish.ts
```ts title="src/strategies/publish.ts"
import {
AbstractBatchJobStrategy,
BatchJobService,
@@ -41,7 +41,7 @@ The batch job strategy class must extend the `AbstractBatchJobStrategy` class wh
For example, you can define the following class in the file you created:
```ts title=src/strategies/import.ts
```ts title="src/strategies/import.ts"
import {
AbstractBatchJobStrategy,
BatchJobService,
+7 -7
View File
@@ -34,7 +34,7 @@ Create the file `src/services/memcached-cache.ts` which will hold your cache ser
Add the following content to the file:
```ts title=src/services/memcached-cache.ts
```ts title="src/services/memcached-cache.ts"
import { ICacheService } from "@medusajs/types"
class MemcachedCacheService implements ICacheService {
@@ -70,7 +70,7 @@ The `constructor` method of a service allows you to prepare any third-party clie
Heres an example of how you can use the `constructor` to create a memcached instance and save the modules options:
```ts title=src/services/memcached-cache.ts
```ts title="src/services/memcached-cache.ts"
import { ICacheService } from "@medusajs/types"
import Memcached from "memcached"
@@ -117,7 +117,7 @@ The `get` method allows you to retrieve the value of a cached item based on its
Heres an example implementation of this method for a Memcached service:
```ts title=src/services/memcached-cache.ts
```ts title="src/services/memcached-cache.ts"
class MemcachedCacheService implements ICacheService {
// ...
async get<T>(cacheKey: string): Promise<T | null> {
@@ -148,7 +148,7 @@ The `set` method is used to set an item in the cache. It accepts three parameter
Heres an example of an implementation of this method for a Memcached service:
```ts title=src/services/memcached-cache.ts
```ts title="src/services/memcached-cache.ts"
class MemcachedCacheService implements ICacheService {
// ...
async set(
@@ -178,7 +178,7 @@ The method accepts a string as a first parameter, which is the key of the item t
Heres an example of an implementation of this method for a Memcached service:
```ts title=src/services/memcached-cache.ts
```ts title="src/services/memcached-cache.ts"
class MemcachedCacheService implements ICacheService {
// ...
async invalidate(key: string): Promise<void> {
@@ -203,7 +203,7 @@ After implementing the cache service, you must export it so that the Medusa back
Create the file `src/index.ts` with the following content:
```ts title=src/index.ts
```ts title="src/index.ts"
import { ModuleExports } from "@medusajs/modules-sdk"
import {
@@ -231,7 +231,7 @@ You can test your module in the Medusa backend by referencing it in the configur
To do that, add the module to the exported configuration in `medusa-config.js` as follows:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -40,7 +40,7 @@ npm install @medusajs/cache-inmemory
In `medusa-config.js`, add the following to the exported object:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
+1 -1
View File
@@ -52,7 +52,7 @@ Where `<YOUR_REDIS_URL>` is a connection URL to your Redis instance.
In `medusa-config.js`, add the following to the exported object:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -20,7 +20,7 @@ Entities can only be placed in the top level of the `src/models` directory. So,
:::
```ts title=src/models/post.ts
```ts title="src/models/post.ts"
import {
BeforeInsert,
Column,
@@ -33,7 +33,7 @@ In the file you created, you can import the entity youre extending from the c
Heres an example of extending the Product entity:
```ts title=src/models/product.ts
```ts title="src/models/product.ts"
import { Column, Entity } from "typeorm"
import {
// alias the core entity to not cause a naming conflict
@@ -55,7 +55,7 @@ If youre using JavaScript instead of TypeScript in your implementation, you c
To ensure that TypeScript is aware of your extended entity and affects the typing of the Medusa package itself, create the file `src/index.d.ts` with the following content:
```ts title=src/index.d.ts
```ts title="src/index.d.ts"
export declare module "@medusajs/medusa/dist/models/product" {
declare interface Product {
customAttribute: string;
@@ -81,7 +81,7 @@ You can learn how to create or generate a migration in [this documentation](./mi
Heres an example of a migration of the entity extended in this guide:
```ts title=src/migration/1680013376180-changeProduct.ts
```ts title="src/migration/1680013376180-changeProduct.ts"
import { MigrationInterface, QueryRunner } from "typeorm"
class changeProduct1680013376180 implements MigrationInterface {
@@ -140,7 +140,7 @@ To change that and ensure your custom attribute is returned in your request, you
For example, if you added a custom attribute in the `Product` entity and you want to ensure it's returned in all the product's store API Routes (API Routes under the prefix `/store/products`), you can create a file under the `src/loaders` directory in your Medusa backend with the following content:
```ts title=src/loaders/extend-product-fields.ts
```ts title="src/loaders/extend-product-fields.ts"
export default async function () {
const imports = (await import(
"@medusajs/medusa/dist/api/routes/store/products/index"
@@ -39,7 +39,7 @@ A data source is Typeorms connection settings that allows you to connect to y
Heres an example of the implementation of the extended Product repository:
```ts title=src/repositories/product.ts
```ts title="src/repositories/product.ts"
import { Product } from "@medusajs/medusa"
import {
dataSource,
@@ -87,7 +87,7 @@ You can now use your extended repository in other resources such as services or
Heres an example of using it in an API Route:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -22,7 +22,7 @@ If you haven't created a custom repository, you can access the default repositor
For example, to retrieve the default repository of an entity in a service:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { Post } from "../models/post"
class PostService extends TransactionBaseService {
@@ -41,7 +41,7 @@ class PostService extends TransactionBaseService {
Another example is retrieving the default repository of an entity in an API Route:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -110,7 +110,7 @@ To access a custom repository within an API Route, use the `MedusaRequest` objec
For example:
```ts title=src/store/custom/route.ts
```ts title="src/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -141,7 +141,7 @@ As custom repositories are registered in the [dependency container](../fundament
For example:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { PostRepository } from "../repositories/post"
class PostService extends TransactionBaseService {
@@ -173,7 +173,7 @@ A subscriber handler function can resolve a repository using the `container` pro
For example:
```ts title=src/subscribers/post-handler.ts
```ts title="src/subscribers/post-handler.ts"
import {
type SubscriberArgs,
} from "@medusajs/medusa"
@@ -29,7 +29,7 @@ Create the file `services/event-bus-custom.ts` which will hold your event bus se
Add the following content to the file:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
import { EmitData, EventBusTypes } from "@medusajs/types"
import { AbstractEventBusModuleService } from "@medusajs/utils"
@@ -81,7 +81,7 @@ Heres an example of how you can use the `constructor` to store the options of
<!-- eslint-disable prefer-rest-params -->
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
class CustomEventBus extends AbstractEventBusModuleService {
protected readonly moduleOptions: Record<string, any>
@@ -109,7 +109,7 @@ The `emit` method has two different signatures:
The `options` parameter depends on the event bus integration. For example, the Redis event bus accepts the following options:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
type JobData<T> = {
eventName: string
data: T
@@ -119,7 +119,7 @@ type JobData<T> = {
You can implement your method in a way that supports both signatures by checking the type of the first input. For example:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
class CustomEventBus extends AbstractEventBusModuleService {
// ...
async emit<T>(
@@ -154,7 +154,7 @@ The `subscribe` method accepts three parameters:
The implementation of this method depends on the service youre using for the event bus:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
class CustomEventBus extends AbstractEventBusModuleService {
// ...
subscribe(
@@ -180,7 +180,7 @@ The `unsubscribe` method accepts three parameters:
The implementation of this method depends on the service youre using for the event bus:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
class CustomEventBus extends AbstractEventBusModuleService {
// ...
unsubscribe(
@@ -200,7 +200,7 @@ After implementing the event bus service, you must export it so that the Medusa
Create the file `index.ts` with the following content:
```ts title=services/event-bus-custom.ts
```ts title="services/event-bus-custom.ts"
import { ModuleExports } from "@medusajs/modules-sdk"
import { CustomEventBus } from "./services"
@@ -226,7 +226,7 @@ You can test your module in the Medusa backend by referencing it in the configur
To do that, add the module to the exported configuration in `medusa-config.js` as follows:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -23,7 +23,7 @@ The `eventBusService.subscribe` method receives the name of the event as a first
For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/order-notifier.ts`:
```ts title=src/subscribers/order-notifier.ts
```ts title="src/subscribers/order-notifier.ts"
class OrderNotifierSubscriber {
constructor({ eventBusService }) {
eventBusService.subscribe("order.placed", this.handleOrder)
@@ -99,7 +99,7 @@ You can access any service through the dependencies injected to your subscriber
For example:
```ts title=src/subscribers/order-notifier.ts
```ts title="src/subscribers/order-notifier.ts"
class OrderNotifierSubscriber {
constructor({ productService, eventBusService }) {
this.productService = productService
@@ -115,7 +115,7 @@ class OrderNotifierSubscriber {
You can then use `this.productService` anywhere in your subscribers methods. For example:
```ts title=src/subscribers/order-notifier.ts
```ts title="src/subscribers/order-notifier.ts"
class OrderNotifierSubscriber {
// ...
handleOrder = async (data) => {
@@ -21,7 +21,7 @@ The subscriber file exports a default handler function, and the subscriber's con
For example:
```ts title=src/subscribers/product-update-handler.ts
```ts title="src/subscribers/product-update-handler.ts"
import {
ProductService,
type SubscriberConfig,
@@ -107,7 +107,7 @@ Within your subscriber, you may need to access the Medusa configuration exported
For example:
```ts title=src/subscribers/product-update-handler.ts
```ts title="src/subscribers/product-update-handler.ts"
import {
ProductService,
type SubscriberConfig,
@@ -37,7 +37,7 @@ npm install @medusajs/event-bus-local
In `medusa-config.js`, add the following to the exported object:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -55,7 +55,7 @@ Where `<YOUR_REDIS_URL>` is a connection URL to your Redis instance.
In `medusa-config.js`, add the following to the exported object:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -39,7 +39,7 @@ You can enable a feature by using the backend configurations in `medusa-config.j
For example, to enable the Tax-Inclusive Pricing beta feature, add the following to the exported object in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
featureFlags: {
tax_inclusive_pricing: true,
@@ -44,7 +44,7 @@ You can learn more about services and their naming convention in [this documenta
For example, create the file `src/services/local-file.ts` with the following content:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
import { AbstractFileService } from "@medusajs/medusa"
import {
DeleteFileType,
@@ -106,7 +106,7 @@ You can use a constructor to access services and resources registered in the dep
For example, the local services constructor could be useful to prepare the local upload directory:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
// ...
import * as fs from "fs"
@@ -139,7 +139,7 @@ Another example showcasing how to access resources using dependency injection:
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
type InjectedDependencies = {
logger: Logger
}
@@ -159,7 +159,7 @@ class LocalFileService extends AbstractFileService {
You can access the plugin options in the second parameter passed to the constructor:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
protected serverUrl = "http://localhost:9000"
// ...
@@ -206,7 +206,7 @@ The method is expected to return an object that has the following properties:
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async upload(
@@ -254,7 +254,7 @@ The method is expected to return an object that has the following properties:
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async uploadProtected(
@@ -286,7 +286,7 @@ This method is not expected to return anything.
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async delete(
@@ -320,7 +320,7 @@ You can also return custom properties within the object.
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async getUploadStreamDescriptor({
@@ -359,7 +359,7 @@ The method is expected to return a readable stream.
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async getDownloadStream({
@@ -394,7 +394,7 @@ The method is expected to return a string, being the URL of the file.
An example implementation of this method for the local file service:
```ts title=src/services/local-file.ts
```ts title="src/services/local-file.ts"
class LocalFileService extends AbstractFileService {
async getPresignedDownloadUrl({
@@ -452,7 +452,7 @@ Since the file is uploaded to a local directory `uploads`, you need to configure
To do that, create the file `src/api/index.ts` with the following content:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type { MiddlewaresConfig } from "@medusajs/medusa"
import express from "express"
@@ -162,7 +162,7 @@ The combination of these two commands running at the same time will compile the
For example, if you're making changes in the `medusa` package, run the following command inside the directory of the `medusa` package:
```bash title=packages/medusa
```bash title="packages/medusa"
yarn watch
```
@@ -170,7 +170,7 @@ Make sure the `medusa-dev` command is also running to copy the changes automatic
Alternatively, you can manually run the `build` command every time you want to compile the changes:
```bash title=packages/medusa
```bash title="packages/medusa"
yarn build
```
@@ -19,7 +19,7 @@ The `IdempotencyKeyService` includes methods that can be used to create and upda
You can create an idempotency key within an API Route using the `create` method of the `IdempotencyKeyService`:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -53,7 +53,7 @@ The method handles generating the idempotency key value and saving the idempoten
Alternatively, you can use the `initializeRequest` method that allows you to retrieve an idempotency key based on the value passed in the `Idempotency-Key` header of the request if it exists, or create a new key otherwise. For example:
```ts title=src/api/store/custom/route.ts
```ts title="src/api/store/custom/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -38,7 +38,7 @@ When the loader is defined in a module, it receives the following parameters:
For example, this loader function resolves the `ProductService` and logs in the console the count of products in the Medusa backend:
```ts title=src/loaders/my-loader.ts
```ts title="src/loaders/my-loader.ts"
import {
ProductService,
ConfigModule,
@@ -16,7 +16,7 @@ To log a message, resolve the `logger` registration name using dependency inject
For example, to log a message in a [loader](../loaders/overview.mdx):
```ts title=src/loaders/my-loader.ts
```ts title="src/loaders/my-loader.ts"
import {
ProductService,
ConfigModule,
@@ -85,7 +85,7 @@ If you configured the `LOG_LEVEL` environment variable to a level higher than th
For example:
```ts title=src/loaders/my-loader.ts
```ts title="src/loaders/my-loader.ts"
import {
ProductService,
ConfigModule,
@@ -149,7 +149,7 @@ Where:
Here's an example implementation of `index.ts` from Medusa's Redis Cache module:
```ts title=index.ts
```ts title="index.ts"
import { ModuleExports } from "@medusajs/modules-sdk"
import Loader from "./loaders"
@@ -172,7 +172,7 @@ export default moduleDefinition
To use your module in the Medusa backend, add your module to `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -200,7 +200,7 @@ The way you add your module depends on its type and what options it requires, if
When the module is installed as an NPM package, the value of the `resolve` property should be the name of that package. For example:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -238,7 +238,7 @@ You can reference your module in two ways:
1\. Referencing the directory: In this case, it's assumed that the `index.ts` file that contains the module definition is in the root of the directory you referenced. Using the above example, the file path would be in this case:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -253,7 +253,7 @@ module.exports = {
2\. Referencing `index` file: In this case, it's assumed that the `index.ts` or `index.js` file you're referencing includes the module definition. Using the above example, the file path would be in this case:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -272,7 +272,7 @@ By default, the module shares the same dependency container used across the Medu
The module's scope can be changed using the `resources` property available as part of the module's configurations:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -35,7 +35,7 @@ Once youre done, you should have a `package.json` created in the directory.
In your `package.json` file, add or update the following fields:
```json title=package.json
```json title="package.json"
{
// other fields
"main": "dist/index.js",
@@ -73,7 +73,7 @@ This adds the necessary dependencies for development and publishing, including t
If you don't already have a `tsconfig.json` file, create one in the root of your NPM project with the following content:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"lib": [
@@ -162,7 +162,7 @@ Where `module-name` is the name of your module.
In `medusa-config.js` on your Medusa backend, add your module to the exported configurations:
```js title=medusa-config.js
```js title="medusa-config.js"
module.exports = {
// ...
modules: {
@@ -25,7 +25,7 @@ Creating a Notification Provider is as simple as creating a TypeScript or JavaS
For example, create the file `src/services/email-sender.ts` with the following content:
```ts title=src/services/email-sender.ts
```ts title="src/services/email-sender.ts"
import { AbstractNotificationService } from "@medusajs/medusa"
import { EntityManager } from "typeorm"
@@ -263,7 +263,7 @@ After creating your Notification Provider Service, you must create a [Loader](..
Following the previous example, to make sure the `email-sender` Notification Provider handles the `order.placed` event, create the file `src/loaders/notification.ts` with the following content:
```ts title=src/loaders/notification.ts
```ts title="src/loaders/notification.ts"
import {
MedusaContainer,
NotificationService,
@@ -66,7 +66,7 @@ npm install
Then, make sure to remove the plugins and modules you removed from `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
// previously had plugins
const plugins = []
@@ -86,7 +86,7 @@ These changes may already be available in your Medusa project. They're included
Start by updating your `tsconfig.json` with the following configurations:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"target": "es2019",
@@ -127,7 +127,7 @@ The addition of `"jsx": "react-jsx"` specified how should TypeScript transform J
Next, create the file `tsconfig.server.json` with the following content:
```json title=tsconfig.server.json
```json title="tsconfig.server.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -142,7 +142,7 @@ This is the configuration that will be used to transpile your custom backend cod
Then, create the file `tsconfig.admin.json` with the following content:
```json title=tsconfig.admin.json
```json title="tsconfig.admin.json"
{
"extends": "./tsconfig.json",
"compilerOptions": {
@@ -157,7 +157,7 @@ This is the configuration that will be used when transpiling your admin code.
Finally, update the `build` scripts in your project and add a new `prepare` command:
```json title=package.json
```json title="package.json"
"scripts": {
// other scripts...
"build": "cross-env npm run clean && npm run build:server && npm run build:admin",
@@ -176,7 +176,7 @@ Each of these scripts do the following:
Furthermore, make sure to add `react` to `peerDependencies` along with `react-router-dom` if you're using it:
```json title=package.json
```json title="package.json"
"peerDependencies": {
// other dependencies...
"react": "^18.2.0",
@@ -330,7 +330,7 @@ Plugins often allow developers that will later use them to provide their own opt
Developers that use your plugin will pass options to your plugin in the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -346,7 +346,7 @@ In your plugin's services, you can have access to the option in their constructo
For example:
```js title=src/service/my.ts
```js title="src/service/my.ts"
// In a service in your plugin
class MyService extends TransactionBaseService {
constructor(container, options) {
@@ -370,7 +370,7 @@ All plugins accept an option named `enableUI`. This option is useful mainly if y
A developer using your plugin can pass the `enableUI` option as part of the plugin's options:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -387,7 +387,7 @@ If you're passing your plugin options to third-party services, make sure to omit
For example:
```js title=src/service/test.ts
```js title="src/service/test.ts"
// In a service in your plugin
class MyService extends TransactionBaseService {
constructor(container, options) {
@@ -76,7 +76,7 @@ All plugins accept an option named `enableUI`. This option allows you to disable
You can set the `enableUI` value by passing it as part of the plugin's configurations:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -47,7 +47,7 @@ Before publishing your plugin, make sure you've set the following fields in your
<TabItem value="without-admin" label="Without Admin Customizations" default>
Make sure you add the `publish` script to your `scripts` field:
```json title=package.json
```json title="package.json"
"scripts": {
// other scripts...
"build": "cross-env npm run clean && tsc -p tsconfig.json",
@@ -64,7 +64,7 @@ Before publishing your plugin, make sure you've set the following fields in your
Then, add the following `prepare` and `build` scripts to your `scripts`
```json title=package.json
```json title="package.json"
"scripts": {
// other scripts...
"build:server": "cross-env npm run clean && tsc -p tsconfig.json",
@@ -92,7 +92,7 @@ So, you can ignore files and directories like `src` from the final published NPM
To do that, create the file `.npmignore` with the following content:
```bash title=.npmignore
```bash title=".npmignore"
/lib
node_modules
.DS_store
@@ -43,7 +43,7 @@ For the example in this tutorial, you can create the file `src/loaders/publish.t
To create a scheduled job, add the following code in the file you created, which is `src/loaders/publish.ts` in this example:
```ts title=src/loaders/publish.ts
```ts title="src/loaders/publish.ts"
import { MedusaContainer } from "@medusajs/medusa"
const publishJob = async (
@@ -35,7 +35,7 @@ The scheduled job file exports a default handler function, and the scheduled job
For example:
```ts title=src/loaders/publish.ts
```ts title="src/loaders/publish.ts"
import {
type ProductService,
type ScheduledJobConfig,
@@ -35,7 +35,7 @@ You can learn more about services and their naming convention in [this documenta
For example, create the file `src/services/my-search.ts` with the following content:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
import { AbstractSearchService } from "@medusajs/utils"
class MySearchService extends AbstractSearchService {
@@ -101,7 +101,7 @@ For example:
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
// ...
import { ProductService } from "@medusajs/medusa"
@@ -127,7 +127,7 @@ You can access the plugin options in the second parameter passed to the construc
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
// ...
class MySearchService extends AbstractSearchService {
@@ -177,7 +177,7 @@ The method does not require any specific data type to be returned.
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -195,7 +195,7 @@ The method accepts one parameter, which is a string indicating the name of the i
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -221,7 +221,7 @@ The method should return the response of saving the documents in the search engi
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -250,7 +250,7 @@ The method should return the response of saving the documents in the search engi
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -282,7 +282,7 @@ The method should return the response of deleting the document in the search eng
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -306,7 +306,7 @@ The method should return the response of deleting the documents of that index in
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -333,7 +333,7 @@ Although theres no required data format or type to be returned to the method,
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -366,7 +366,7 @@ The method should return the response of updating the index in the search engine
An example implementation, assuming `client_` would interact with a third-party service:
```ts title=src/services/my-search.ts
```ts title="src/services/my-search.ts"
class MySearchService extends AbstractSearchService {
// ...
@@ -17,7 +17,7 @@ To create a service, create a TypeScript or JavaScript file in `src/services` to
For example, if you want to create a service `PostService`, eventually registered as `postService`, create the file `post.ts` in `src/services` with the following content:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { TransactionBaseService } from "@medusajs/medusa"
class PostService extends TransactionBaseService {
@@ -53,7 +53,7 @@ As the service extends the `TransactionBaseService` class, all resources registe
So, if you want your service to use another service, add it as part of your constructors dependencies and set it to a field inside your services class:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { ProductService } from "@medusajs/medusa"
import { PostRepository } from "../repositories/post"
@@ -70,7 +70,7 @@ class PostService extends TransactionBaseService {
Then, you can use that service anywhere in your custom service. For example:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
class PostService extends TransactionBaseService {
// ...
async getProductCount() {
@@ -91,7 +91,7 @@ However, to actually get an instance of the repository within the service's meth
For example:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { PostRepository } from "../repositories/post"
class PostService extends TransactionBaseService {
@@ -131,7 +131,7 @@ The data returned by the function passed as a parameter to the `atomicPhase_` me
For example, the `PostService`'s `create` method with the `atomicPhase_` method:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
class PostService extends TransactionBaseService {
protected postRepository_: typeof PostRepository
// ...
@@ -169,7 +169,7 @@ There are three lifetime types:
You can set the lifetime of your service by setting the `LIFE_TIME` static property:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { TransactionBaseService } from "@medusajs/medusa"
import { Lifetime } from "awilix"
@@ -188,7 +188,7 @@ Within your service, you may need to access the Medusa configuration exported fr
For example:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import {
ConfigModule,
TransactionBaseService,
@@ -228,7 +228,7 @@ The `@medusajs/medusa` package also provides a `buildQuery` method that allows y
So, for example, to create a method that retrieves a list of posts and the total number of posts available:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import {
FindConfig,
Selector,
@@ -260,7 +260,7 @@ In addition, you can expand relations when retrieving a single item with the hel
For example, to create a method that retrieves a single post:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import {
FindConfig,
TransactionBaseService,
@@ -319,7 +319,7 @@ This assumes you're handling errors in your custom API Route as explained [here]
For example:
```ts title=src/services/post.ts
```ts title="src/services/post.ts"
import { MedusaError } from "@medusajs/utils"
class PostService extends TransactionBaseService {
@@ -33,7 +33,7 @@ In the file, you can import the original service from the Medusa core, then crea
For example, to extend the Product service:
```ts title=src/services/product.ts
```ts title="src/services/product.ts"
import {
ProductService as MedusaProductService,
} from "@medusajs/medusa"
@@ -51,7 +51,7 @@ Within the service, you can add new methods or extend existing ones.
You can also change the lifetime of the service:
```ts title=src/services/product.ts
```ts title="src/services/product.ts"
import { Lifetime } from "awilix"
import {
ProductService as MedusaProductService,
+1 -1
View File
@@ -50,7 +50,7 @@ After initialization, you can use the client's properties and methods to send re
Make sure to set `moduleResolution` in your `tsconfig.json` to `nodenext` or `node`:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"moduleResolution": "nodenext",
+15 -15
View File
@@ -54,7 +54,7 @@ The `MedusaProvider` requires two props:
For example:
```tsx title=src/App.ts
```tsx title="src/App.ts"
import { MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
@@ -90,7 +90,7 @@ Could not find a declaration file for module 'medusa-react'
Make sure to set `moduleResolution` in your `tsconfig.json` to `nodenext` or `node`:
```json title=tsconfig.json
```json title="tsconfig.json"
{
"compilerOptions": {
"moduleResolution": "nodenext",
@@ -115,7 +115,7 @@ To fetch data from the Medusa backend (in other words, perform `GET` requests),
For example, to fetch products from your Medusa backend:
```tsx title=src/Products.ts
```tsx title="src/Products.ts"
import { Product } from "@medusajs/medusa"
import { useProducts } from "medusa-react"
@@ -146,7 +146,7 @@ Instead of the `data` field, the response data is flattened and is part of the h
If the request accepts any parameters, they can be passed as parameters to the `mutate` request. For example:
```tsx title=src/Products.ts
```tsx title="src/Products.ts"
const { products } = useProducts({
expand: "variants",
})
@@ -160,7 +160,7 @@ To create, update, or delete data on the Medusa backend (in other words, perform
For example, to create a cart:
```tsx title=src/Cart.ts
```tsx title="src/Cart.ts"
import { useCreateCart } from "medusa-react"
const Cart = () => {
@@ -360,7 +360,7 @@ The request returns an object containing keys like `mutation` which is a functio
For example:
```tsx title=src/admin/routes/blog/posts/page.tsx
```tsx title="src/admin/routes/blog/posts/page.tsx"
import { useAdminCustomPost } from "medusa-react"
import { useNavigate } from "react-router-dom"
@@ -438,7 +438,7 @@ The request returns an object containing keys like `mutation` which is a functio
For example:
```tsx title=src/admin/routes/blog/posts/[id]/page.tsx
```tsx title="src/admin/routes/blog/posts/[id]/page.tsx"
import { useAdminCustomDelete } from "medusa-react"
import { useNavigate, useParams } from "react-router-dom"
@@ -502,7 +502,7 @@ It accepts an object with the following properties:
For example:
```tsx title=src/Products.ts
```tsx title="src/Products.ts"
import { formatVariantPrice } from "medusa-react"
import { Product, ProductVariant } from "@medusajs/medusa"
@@ -542,7 +542,7 @@ It accepts an object with the following properties:
For example:
```tsx title=src/Products.ts
```tsx title="src/Products.ts"
import { computeVariantPrice } from "medusa-react"
import { Product, ProductVariant } from "@medusajs/medusa"
@@ -587,7 +587,7 @@ It accepts an object with the following properties:
For example:
```tsx title=src/MyComponent.ts
```tsx title="src/MyComponent.ts"
import { formatAmount } from "medusa-react"
const MyComponent = () => {
@@ -617,7 +617,7 @@ It accepts an object with the following properties:
For example:
```tsx title=src/MyComponent.ts
```tsx title="src/MyComponent.ts"
import { computeAmount } from "medusa-react"
const MyComponent = () => {
@@ -655,7 +655,7 @@ To use `CartProvider`, you first have to insert it somewhere in your component t
For example:
```tsx title=src/App.ts
```tsx title="src/App.ts"
import { CartProvider, MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
@@ -695,7 +695,7 @@ The `useCart` hook returns an object with the following properties:
For example:
```tsx title=src/Cart.ts
```tsx title="src/Cart.ts"
import * as React from "react"
import { useCart } from "medusa-react"
@@ -745,7 +745,7 @@ To use `SessionProvider`, you first have to insert it somewhere in your componen
For example:
```tsx title=src/App.ts
```tsx title="src/App.ts"
import { SessionProvider, MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
@@ -773,7 +773,7 @@ Then, in any of the child components, you can use the `useSessionHook` hook expo
For example:
```tsx title=src/Products.ts
```tsx title="src/Products.ts"
const Products = () => {
const { addItem } = useSessionCart()
// ...
@@ -32,7 +32,7 @@ Fulfillment providers are loaded and installed on the backend startup.
The first step is to create a JavaScript or TypeScript file under `src/services`. For example, create the file `src/services/my-fulfillment.ts` with the following content:
```ts title=src/services/my-fulfillment.ts
```ts title="src/services/my-fulfillment.ts"
import {
AbstractFulfillmentService,
Cart,
@@ -60,7 +60,7 @@ The first step to create a payment processor is to create a JavaScript or TypeSc
For example, create the file `src/services/my-payment-processor.ts` with the following content:
```ts title=src/services/my-payment-processor.ts
```ts title="src/services/my-payment-processor.ts"
import {
AbstractPaymentProcessor,
PaymentProcessorContext,
@@ -19,7 +19,7 @@ This guide only explains how to override the cart completion strategy. Its hi
Create a TypeScript or JavaScript file in `src/strategies` of your Medusa backend project with a class that extends the `AbstractCartCompletionStrategy` class:
```ts title=src/strategies/cart-completion.ts
```ts title="src/strategies/cart-completion.ts"
import {
AbstractCartCompletionStrategy,
CartCompletionResponse,
@@ -52,7 +52,7 @@ You can use a constructor to access services and resources registered in the dep
<!-- eslint-disable prefer-rest-params -->
```ts title=src/strategies/cart-completion.ts
```ts title="src/strategies/cart-completion.ts"
// ...
import { IdempotencyKeyService } from "@medusajs/medusa"
@@ -39,7 +39,7 @@ To subscribe to an event, you must create a [subscriber](../../../development/ev
Create the file `src/subscribers/customer-confirmation.ts` with the following content:
```ts title=src/subscribers/customer-confirmation.ts
```ts title="src/subscribers/customer-confirmation.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -70,7 +70,7 @@ In this method, you should typically send an email to the customer. You can plac
For example, you can implement this subscriber to send emails using [SendGrid](../../../plugins/notifications/sendgrid.mdx):
```ts title=src/subscribers/customer-confirmation.ts
```ts title="src/subscribers/customer-confirmation.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -117,7 +117,7 @@ If the notification provider youre using already implements the logic to hand
For example:
```ts title=src/loaders/customer-confirmation.ts
```ts title="src/loaders/customer-confirmation.ts"
import {
MedusaContainer,
NotificationService,
@@ -41,7 +41,7 @@ To subscribe to and handle an event, you must create a [subscriber](../../../dev
Create the file `src/subscribers/gift-card.ts` with the following content:
```ts title=src/subscribers/gift-card.ts
```ts title="src/subscribers/gift-card.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -72,7 +72,7 @@ In this method, you should typically send an email to the customer. You can plac
For example, you can implement this subscriber to send emails using [SendGrid](../../../plugins/notifications/sendgrid.mdx):
```ts title=src/subscribers/gift-card.ts
```ts title="src/subscribers/gift-card.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -125,7 +125,7 @@ If the notification provider youre using already implements the logic to hand
For example:
```ts title=src/loaders/gift-card-event.ts
```ts title="src/loaders/gift-card-event.ts"
import {
MedusaContainer,
NotificationService,
@@ -47,7 +47,7 @@ Create a file in the `src/services` directory that will hold your custom invento
In that file, add the following content:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
import {
CreateInventoryItemInput,
CreateInventoryLevelInput,
@@ -302,7 +302,7 @@ type InventoryItemDTO = {
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -360,7 +360,7 @@ type ReservationItemDTO = {
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -417,7 +417,7 @@ type InventoryLevelDTO = {
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -452,7 +452,7 @@ This method is expected to return the inventory item as an object.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -491,7 +491,7 @@ This method is expected to return the inventory level as an object.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -530,7 +530,7 @@ This method is expected to return the inventory level as an object.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -572,7 +572,7 @@ This method is expected to return the newly created reservation item.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -605,7 +605,7 @@ This method is expected to return the newly created inventory item.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -643,7 +643,7 @@ This method is expected to return the newly created inventory level.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -677,7 +677,7 @@ This method is expected to return the updated reservation item.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -719,7 +719,7 @@ This method is expected to return the updated inventory item.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -766,7 +766,7 @@ This method is expected to return the updated inventory level.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -810,7 +810,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -843,7 +843,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -878,7 +878,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -913,7 +913,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -947,7 +947,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -984,7 +984,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -1021,7 +1021,7 @@ This method is expected to return the updated location level.
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -1074,7 +1074,7 @@ This method is expected to return a boolean value indicating whether the invento
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -1110,7 +1110,7 @@ This method is expected to return a number being the available quantity of the i
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -1143,7 +1143,7 @@ This method is expected to return a number being the stocked quantity of the ite
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -1176,7 +1176,7 @@ This method is expected to return a number being the reserved quantity of the it
For example:
```ts title=src/services/inventory.ts
```ts title="src/services/inventory.ts"
class InventoryService implements IInventoryService {
// ...
@InjectEntityManager()
@@ -47,7 +47,7 @@ Create a file in the `src/services` directory that will hold your custom stock l
In that file, add the following content:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
import {
CreateStockLocationInput,
FilterableStockLocationProps,
@@ -168,7 +168,7 @@ type StockLocationDTO = {
Heres an example implementation of the method:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -199,7 +199,7 @@ It accepts the exact same parameters as the [list method](#implementing-list-met
Heres an example implementation of the method:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -234,7 +234,7 @@ This method returns the location as an object.
For example:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -275,7 +275,7 @@ The method is expected to return the created location as an object.
For example:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -313,7 +313,7 @@ This method is expected to return the updated location object.
For example:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -348,7 +348,7 @@ This method is not expected to return anything.
For example:
```ts title=src/services/stock-location.ts
```ts title="src/services/stock-location.ts"
class StockLocationService implements IStockLocationService {
// ...
@InjectEntityManager()
@@ -45,7 +45,7 @@ You can learn more about subscribers in the [Subscribers documentation](../../
Create the file `src/subscribers/order-claim.ts` with the following content:
```ts title=src/subscribers/order-claim.ts
```ts title="src/subscribers/order-claim.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -88,7 +88,7 @@ In this method, you should typically send an email to the customer. You can plac
For example, you can implement this subscriber to send emails using SendGrid:
```ts title=src/subscribers/order-claim.ts
```ts title="src/subscribers/order-claim.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -129,7 +129,7 @@ If the notification provider youre using already implements the logic to hand
For example:
```ts title=src/loaders/order-claim.ts
```ts title="src/loaders/order-claim.ts"
import {
MedusaContainer,
NotificationService,
@@ -37,7 +37,7 @@ To subscribe to an event, you must create a [subscriber](../../../development/ev
Create the file `src/subscribers/order-placed.ts` with the following content:
```ts title=src/subscribers/order-placed.ts
```ts title="src/subscribers/order-placed.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -74,7 +74,7 @@ This example is only used to illustrate how the functionality can be implemented
For example, you can implement this subscriber to send emails using [SendGrid](../../../plugins/notifications/sendgrid.mdx):
```ts title=src/subscribers/order-placed.ts
```ts title="src/subscribers/order-placed.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -129,7 +129,7 @@ If the notification provider youre using already implements the logic to hand
For example:
```ts title=src/loaders/customer-confirmation.ts
```ts title="src/loaders/customer-confirmation.ts"
import {
MedusaContainer,
NotificationService,
+11 -11
View File
@@ -25,7 +25,7 @@ Medusa provides the necessary features to build a customizable shopping experien
<LargeCardList colSize={6}>
<LargeCard
Icon={Icons['check-circle-solid']}
title='Orders'
title="'Orders'"
action={{
label: 'Learn more',
href: '/modules/orders/overview'
@@ -42,7 +42,7 @@ Medusa provides the necessary features to build a customizable shopping experien
</LargeCard>
<LargeCard
Icon={Icons['building-solid']}
title='Inventory (Multi-Warehouse)'
title="'Inventory (Multi-Warehouse)'"
action={{
label: 'Learn more',
href: '/modules/multiwarehouse/overview'
@@ -57,7 +57,7 @@ Medusa provides the necessary features to build a customizable shopping experien
</LargeCard>
<LargeCard
Icon={Icons['shopping-cart-solid']}
title='Cart and Checkout'
title="'Cart and Checkout'"
action={{
label: 'Learn more',
href: '/modules/carts-and-checkout/overview'
@@ -73,7 +73,7 @@ Medusa provides the necessary features to build a customizable shopping experien
</LargeCard>
<LargeCard
Icon={Icons['users-solid']}
title='Customers'
title="'Customers'"
action={{
label: 'Learn more',
href: '/modules/customers/overview'
@@ -95,7 +95,7 @@ Medusa's products configuration allows managing products of different types incl
<LargeCardList colSize={6}>
<LargeCard
Icon={Icons['tag-solid']}
title='Products'
title="'Products'"
action={{
label: 'Learn more',
href: '/modules/products/overview'
@@ -112,7 +112,7 @@ Medusa's products configuration allows managing products of different types incl
</LargeCard>
<LargeCard
Icon={Icons['gift-solid']}
title='Gift Cards'
title="'Gift Cards'"
action={{
label: 'Learn more',
href: '/modules/gift-cards/overview'
@@ -129,7 +129,7 @@ Medusa's products configuration allows managing products of different types incl
<LargeCard
Icon={Icons['currency-dollar-solid']}
title='Price Lists'
title="'Price Lists'"
action={{
label: 'Learn more',
href: '/modules/price-lists/overview'
@@ -146,7 +146,7 @@ Medusa's products configuration allows managing products of different types incl
<LargeCard
Icon={Icons['receipt-percent']}
title='Discounts'
title="'Discounts'"
action={{
label: 'Learn more',
href: '/modules/discounts/overview'
@@ -169,7 +169,7 @@ Medusa's multi-region setup and sales channels allow businesses to sell internat
<LargeCardList colSize={6}>
<LargeCard
Icon={Icons['globe-europe-solid']}
title='Region and Currencies'
title="'Region and Currencies'"
action={{
label: 'Learn more',
href: '/modules/regions-and-currencies/overview'
@@ -185,7 +185,7 @@ Medusa's multi-region setup and sales channels allow businesses to sell internat
</LargeCard>
<LargeCard
Icon={Icons['cash-solid']}
title='Taxes'
title="'Taxes'"
action={{
label: 'Learn more',
href: '/modules/taxes/overview'
@@ -203,7 +203,7 @@ Medusa's multi-region setup and sales channels allow businesses to sell internat
<LargeCard
Icon={Icons['channels-solid']}
title='Sales Channels'
title="'Sales Channels'"
action={{
label: 'Learn more',
href: '/modules/sales-channels/overview'
@@ -19,7 +19,7 @@ If youre interested in learning what a price selection strategy is and how it
Create a TypeScript or JavaScript file in `src/strategies` of your Medusa backend project with a class that extends the `AbstractPriceSelectionStrategy` class:
```ts title=src/strategies/price.ts
```ts title="src/strategies/price.ts"
import {
AbstractPriceSelectionStrategy,
PriceSelectionContext,
@@ -51,7 +51,7 @@ You can resolve resources like services or repositories using [dependency inject
For example:
```ts title=src/strategies/price.ts
```ts title="src/strategies/price.ts"
import {
AbstractPriceSelectionStrategy,
CustomerService,
@@ -90,7 +90,7 @@ If you are using an existing Medusa database, you can skip this step.
Migrations are used to create your database schema. Before you can run migrations, add in your `package.json` the following scripts:
```json title=package.json
```json title="package.json"
"scripts": {
//...other scripts
"product:migrations:run": "medusa-product-migrations-up",
@@ -103,7 +103,7 @@ The first command runs the migrations, and the second command allows you to opti
<Details>
<Summary>Seed file</Summary>
```js title=seed-data.js
```js title="seed-data.js"
const productCategoriesData = [
{
id: "category-0",
@@ -210,7 +210,7 @@ Next.js uses Webpack for compilation. Since quite a few of the dependencies used
To do that, add the `serverComponentsExternalPackages` option in `next.config.js`:
```js title=next.config.js
```js title="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
@@ -235,7 +235,7 @@ This guide uses Next.js's App Router.
For example, create the file `app/api/products/route.ts` with the following content:
```ts title=app/api/products/route.ts
```ts title="app/api/products/route.ts"
import { NextResponse } from "next/server"
import {
@@ -271,7 +271,7 @@ This section includes some examples of the different functionalities or ways you
### List Products
```ts title=app/api/products/route.ts
```ts title="app/api/products/route.ts"
import { NextResponse } from "next/server"
import {
@@ -289,7 +289,7 @@ export async function GET(request: Request) {
### Retrieve Product by Id
```ts title=app/api/product/[id]/route.ts
```ts title="app/api/product/[id]/route.ts"
import { NextResponse } from "next/server"
import {
@@ -313,7 +313,7 @@ export async function GET(
### Retrieve Product by Handle
```ts title=app/api/product/[handle]/route.ts
```ts title="app/api/product/[handle]/route.ts"
import { NextResponse } from "next/server"
import {
@@ -337,7 +337,7 @@ export async function GET(
### Retrieve Categories
```ts title=app/api/categories/route.ts
```ts title="app/api/categories/route.ts"
import { NextResponse } from "next/server"
import {
@@ -355,7 +355,7 @@ export async function GET(request: Request) {
### Retrieve Category by Handle
```ts title=app/api/category/[handle]/route.ts
```ts title="app/api/category/[handle]/route.ts"
import { NextResponse } from "next/server"
import {
@@ -19,7 +19,7 @@ A tax provider class should be defined in a TypeScript or JavaScript file under
For example, you can create the file `src/services/my-tax.ts` with the following content:
```ts title=src/services/my-tax.ts
```ts title="src/services/my-tax.ts"
import {
AbstractTaxService,
ItemTaxCalculationLine,
@@ -49,7 +49,7 @@ Since the class extends `AbstractTaxService`, it must implement its abstract met
You can use a constructor to access services and resources registered in the dependency container using dependency injection. For example:
```ts title=src/services/my-tax.ts
```ts title="src/services/my-tax.ts"
// ...
import { LineItemService } from "@medusajs/medusa"
@@ -79,7 +79,7 @@ Every tax provider must have a unique identifier. The identifier is defined as a
Add the static property `identifier` in your tax provider class:
```ts title=src/services/my-tax.ts
```ts title="src/services/my-tax.ts"
class MyTaxService extends AbstractTaxService {
static identifier = "my-tax"
// ...
@@ -161,7 +161,7 @@ The Medusa backend determines whether an object in the returned array is a shipp
For example, the `system` tax provider returns the tax calculation line items in the first parameter and the tax calculation shipping methods in the second parameter as is:
```ts title=src/services/my-tax.ts
```ts title="src/services/my-tax.ts"
// ...
class SystemTaxService extends AbstractTaxService {
@@ -21,7 +21,7 @@ A tax calculation strategy should be defined in a TypeScript or JavaScript file
For example, you can create the file `src/strategies/tax-calculation.ts` with the following content:
```ts title=src/strategies/tax-calculation.ts
```ts title="src/strategies/tax-calculation.ts"
import {
ITaxCalculationStrategy,
LineItem,
@@ -52,7 +52,7 @@ Note that you add a basic implementation of the `calculate` method because it
You can use a constructor to access services and resources registered in the dependency container using dependency injection. For example:
```ts title=src/strategies/tax-calculation.ts
```ts title="src/strategies/tax-calculation.ts"
// ...
import {
LineItemService,
@@ -52,7 +52,7 @@ You can learn how to [retrieve and use services](../../../development/services/c
Another way you can use the `CartService` to calculate taxes is using the method `decorateTotals`:
```ts title=src/api/store/line-taxes/[cart_id]/route.ts
```ts title="src/api/store/line-taxes/[cart_id]/route.ts"
import { CartService } from "@medusajs/medusa"
import type {
MedusaRequest,
@@ -56,7 +56,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Create the file `src/models/role.ts` with the following content:
```ts title=src/models/role.ts
```ts title="src/models/role.ts"
import {
BeforeInsert,
Column,
@@ -129,7 +129,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Then, create the file `src/repositories/role.ts` with the following content:
```ts title=src/repositories/role.ts
```ts title="src/repositories/role.ts"
import { Role } from "../models/role"
import {
dataSource,
@@ -143,7 +143,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Next, create the file `src/models/permission.ts` with the following content:
```ts title=src/models/permission.ts
```ts title="src/models/permission.ts"
import {
BeforeInsert,
Column,
@@ -182,7 +182,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Then, create the file `src/repositories/permission.ts` with the following content:
```ts title=src/repositories/permission.ts
```ts title="src/repositories/permission.ts"
import { Permission } from "../models/permission"
import {
dataSource,
@@ -198,7 +198,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Create the file `src/models/user.ts` with the following content:
```ts title=src/models/user.ts
```ts title="src/models/user.ts"
import {
Column,
Entity,
@@ -228,7 +228,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Next, create the file `src/models/store.ts` with the following content:
```ts title=src/models/store.ts
```ts title="src/models/store.ts"
import { Entity, JoinColumn, OneToMany } from "typeorm"
import {
// alias the core entity to not cause a naming conflict
@@ -248,7 +248,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
Optionally, if youre using TypeScript, create the file `src/index.d.ts` with the following content:
```ts title=src/index.d.ts
```ts title="src/index.d.ts"
import { Role } from "./models/role"
export declare module "@medusajs/medusa/dist/models/user" {
@@ -272,7 +272,7 @@ So, the first step would be to create the `Role` and `Permission` entities to re
<!-- eslint-disable max-len -->
```ts title=src/migrations/1693225851284-AddRolesAndPermissions.ts
```ts title="src/migrations/1693225851284-AddRolesAndPermissions.ts"
import { MigrationInterface, QueryRunner, Table, TableIndex } from "typeorm"
export class AddRolesAndPermissions1693225851284 implements MigrationInterface {
@@ -352,7 +352,7 @@ Since the Medusa backend uses Express, you can create a middleware and attach it
Create the file `src/api/middlewares.ts` with the following content:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type {
MiddlewaresConfig,
UserService,
@@ -488,7 +488,7 @@ Furthermore, you may need to extend core services if you need to perform actions
Start by creating the file `src/services/permission.ts` with the following content:
```ts title=src/services/permission.ts
```ts title="src/services/permission.ts"
import { TransactionBaseService } from "@medusajs/medusa"
import { Permission } from "../models/permission"
import PermissionRepository from "../repositories/permission"
@@ -533,7 +533,7 @@ Furthermore, you may need to extend core services if you need to perform actions
Next, create the file `src/services/user.ts` with the following content:
```ts title=src/services/user.ts
```ts title="src/services/user.ts"
import {
UserService as MedusaUserService, User,
} from "@medusajs/medusa"
@@ -556,7 +556,7 @@ Furthermore, you may need to extend core services if you need to perform actions
Then, create the file `src/services/role.ts` with the following content:
```ts title=src/services/role.ts
```ts title="src/services/role.ts"
import { TransactionBaseService } from "@medusajs/medusa"
import { Role } from "../models/role"
import RoleRepository from "../repositories/role"
@@ -661,7 +661,7 @@ Furthermore, you may need to extend core services if you need to perform actions
Start by creating the file `src/api/admin/roles/route.ts` with the following content:
```ts title=src/api/admin/roles/route.ts
```ts title="src/api/admin/roles/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -697,7 +697,7 @@ Furthermore, you may need to extend core services if you need to perform actions
Next, create the file `src/api/routes/admin/roles/[id]/user/[user_id]/route.ts` with the following content:
```ts title=src/api/routes/admin/roles/[id]/user/[user_id]/route.ts
```ts title="src/api/routes/admin/roles/[id]/user/[user_id]/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -37,7 +37,7 @@ To subscribe to an event, you must create a [subscriber](../../../development/ev
Create the file `src/subscribers/invite-created.ts` with the following content:
```ts title=src/subscribers/invite-created.ts
```ts title="src/subscribers/invite-created.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -78,7 +78,7 @@ In this method, you should typically send an email to the user. You can place an
For example, you can implement this subscriber to send emails using SendGrid:
```ts title=src/subscribers/invite.ts
```ts title="src/subscribers/invite.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -123,7 +123,7 @@ If the notification provider youre using already implements the logic to hand
For example:
```ts title=src/loaders/customer-confirmation.ts
```ts title="src/loaders/customer-confirmation.ts"
import {
MedusaContainer,
NotificationService,
@@ -111,7 +111,7 @@ Where `<YOUR_SEGMENT_WRITE_KEY>` is the Write Key shown on the page of the Segme
Finally, in `medusa-config.js`, add the following new item to the `plugins` array:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -155,7 +155,7 @@ In some cases, you might want to track more events or custom events. You can do
For example, you can add the following [subscriber](../../development/events/subscribers.mdx) to listen to the `customer.created` event and add tracking for every customer created:
```ts title=src/subscribers/customer.ts
```ts title="src/subscribers/customer.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -38,7 +38,7 @@ npm install medusa-plugin-contentful
Next, add the plugin into the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -76,7 +76,7 @@ When the plugin syncs data between Contentful and Medusa, it expects a set of fi
For example, to change the name of the products `title` field, pass the following option to the plugin:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -168,7 +168,7 @@ npm install --save-dev contentful-migration
Create the file `src/loaders/contentful-migrations/product.ts` with the following content:
```ts title=src/loaders/contentful-migrations/product.ts
```ts title="src/loaders/contentful-migrations/product.ts"
import Migration, {
MigrationContext,
} from "contentful-migration"
@@ -247,7 +247,7 @@ npm install --save-dev contentful-migration
Create the file `src/loaders/contentful-migrations/product-variant.ts` with the following content:
```ts title=src/loaders/contentful-migrations/product-variant.ts
```ts title="src/loaders/contentful-migrations/product-variant.ts"
import Migration, {
MigrationContext,
} from "contentful-migration"
@@ -292,7 +292,7 @@ npm install --save-dev contentful-migration
Create the file `src/loaders/contentful-migrations/product-collection.ts` with the following content:
```ts title=src/loaders/contentful-migrations/product-collection.ts
```ts title="src/loaders/contentful-migrations/product-collection.ts"
import Migration, {
MigrationContext,
} from "contentful-migration"
@@ -325,7 +325,7 @@ npm install --save-dev contentful-migration
Create the file `src/loaders/contentful-migrations/product-type.ts` with the following content:
```ts title=src/loaders/contentful-migrations/product-type.ts
```ts title="src/loaders/contentful-migrations/product-type.ts"
import Migration, {
MigrationContext,
} from "contentful-migration"
@@ -358,7 +358,7 @@ npm install --save-dev contentful-migration
Create the file `src/loaders/contentful-migrations/region.ts` with the following content:
```ts title=src/loaders/contentful-migrations/region.ts
```ts title="src/loaders/contentful-migrations/region.ts"
import Migration, {
MigrationContext,
} from "contentful-migration"
@@ -404,7 +404,7 @@ npm install --save-dev contentful-migration
Finally, create a [loader](../../development/loaders/overview.mdx) at `src/loaders/index.ts` with the following content:
```ts title=src/loaders/index.ts
```ts title="src/loaders/index.ts"
import {
ConfigModule,
StoreService,
+1 -1
View File
@@ -146,7 +146,7 @@ Where:
Finally, open `medusa-config.js` and add the following new item to the `plugins` array:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -40,7 +40,7 @@ npm install medusa-plugin-brightpearl
Finally, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -37,7 +37,7 @@ npm install @medusajs/file-local
Then, configure your `medusa-config.js` to include the plugin with the required options:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -80,7 +80,7 @@ If this configuration is not added, youll receive the error ["next/image Un-c
In `next.config.js` add the following option in the exported object:
```js title=next.config.js
```js title="next.config.js"
const { withStoreConfig } = require("./store-config")
// ...
@@ -92,7 +92,7 @@ Where `<ENDPOINT>` is the URL of your MinIO backend, `<BUCKET>` is the name of t
Finally, configure your `medusa-config.js` to include the plugin with the required options:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -147,7 +147,7 @@ MINIO_PRIVATE_BUCKET=exports
Then, add a new option to the plugins options in `medusa-config.js`:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -175,7 +175,7 @@ Where `<YOUR_PRIVATE_ACCESS_KEY>` and `<YOUR_PRIVATE_SECRET_KEY>` are the access
Then, add two new options to the plugins options in `medusa-config.js`:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -201,7 +201,7 @@ If this configuration is not added, youll receive the error ["next/image Un-c
In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
```jsx title="next.config.js"
const { withStoreConfig } = require("./store-config")
// ...
@@ -106,7 +106,7 @@ npm install medusa-file-s3
Then, in `medusa-config.js`, add to the `plugins` array the following new item:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -164,7 +164,7 @@ You can pass additional AWS configurations, such as `customUserAgent`, in the pl
For example:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -212,7 +212,7 @@ If this configuration is not added, youll receive the error ["next/image Un-c
In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
```jsx title="next.config.js"
const { withStoreConfig } = require("./store-config")
// ...
@@ -108,7 +108,7 @@ Where:
Finally, in `medusa-config.js` add a new item to the `plugins` array:
```jsx title=medusa-config.js
```jsx title="medusa-config.js"
const plugins = [
// ...
{
@@ -160,7 +160,7 @@ If this configuration is not added, youll receive the error ["next/image Un-
In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
```jsx title="next.config.js"
const { withStoreConfig } = require("./store-config")
// ...
@@ -30,7 +30,7 @@ npm install medusa-fulfillment-manual
Finally, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -36,7 +36,7 @@ npm install medusa-fulfillment-webshipper
Next, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -62,7 +62,7 @@ Make sure to replace `<YOUR_API_KEY>` with your API Key and `<YOUR_NEWSLETTER_LI
Open `medusa-config.js` and add the new plugin into the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...,
{
@@ -123,7 +123,7 @@ To subscribe users to the newsletter without using this API Route or at a specif
Heres an example of using the `mailchimpService` in an API Route:
```ts title=src/api/store/subscribe/route.ts
```ts title="src/api/store/subscribe/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -3943,7 +3943,7 @@ Where `<ORDER_PLACED_TEMPLATE_ID` is the ID of your template for order placed em
Finally, in your `medusa-config.js` file, add the SendGrid plugin into the array of plugins:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...,
{
@@ -4000,7 +4000,7 @@ You can resolve the SendGrid service to send emails from your custom services or
For example, in an API Route:
```ts title=src/api/store/email/route.ts
```ts title="src/api/store/email/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -78,7 +78,7 @@ npm install medusa-plugin-slack-notification
After that, open `medusa-config.js` and add the new plugin with its configurations in the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...,
{
@@ -55,7 +55,7 @@ Make sure to replace `<YOUR_ACCOUNT_SID>`, `<YOUR_AUTH_TOKEN>`, and `<YOUR_TWILI
Finally, add the plugin and its options in the `medusa-config.js` file to the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -85,7 +85,7 @@ For this example to work, you'll need to have an [event bus module](../../develo
Create the file `src/subscriber/sms.ts` in your Medusa backend with the following content:
```ts title=src/subscriber/sms.ts
```ts title="src/subscriber/sms.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -30,7 +30,7 @@ npm install medusa-plugin-discount-generator
Finally, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -65,7 +65,7 @@ The `DiscountGeneratorService` has one method `generateDiscount`. This method re
Here's an example of using the service in an API Route:
```ts title=src/api/store/generate-discount-code/route.ts
```ts title="src/api/store/generate-discount-code/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -44,7 +44,7 @@ Where `<YOUR_ACCESS_KEY>` is your ipstack accounts access key. Its availab
Finally, add the IP lookup plugin into the plugins array exported as part of the Medusa configuration in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// other plugins...
{
@@ -80,7 +80,7 @@ You can learn more about creating an API Route [here](../../development/api-rout
:::
```ts title=src/api/store/customer-region/route.ts
```ts title="src/api/store/customer-region/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -124,7 +124,7 @@ For example, you can attach it to all `/store` routes to ensure the customers
<!-- eslint-disable @typescript-eslint/no-var-requires -->
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import type { MiddlewaresConfig } from "@medusajs/medusa"
const { preCartCreation } = require(
"medusa-plugin-ip-lookup/api/medusa-middleware"
@@ -44,7 +44,7 @@ npm install medusa-plugin-restock-notification
Then, add the plugin into the plugins array exported as part of the Medusa configuration in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// other plugins...
{
@@ -116,7 +116,7 @@ The SendGrid plugin already listens to and handles the `restock-notification.res
Here's an example of a [subscriber](../../development/events/subscribers.mdx) that listens to the `restock-notification.restocked` event and uses the [SendGrid plugin](../notifications/sendgrid.mdx) to send the subscribed customers an email:
```ts title=src/subscribers/restock-notification.ts
```ts title="src/subscribers/restock-notification.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -37,7 +37,7 @@ npm install medusa-plugin-wishlist
Finally, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -64,7 +64,7 @@ Where:
Finally, in `medusa-config.js`, add the Klarna plugin to the `plugins` array with the necessary configurations:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// other plugins...
{
@@ -62,7 +62,7 @@ Notice that during development its highly recommended to set `PAYPAL_SANDBOX`
Then, in `medusa-config.js`, add the PayPal plugin to the `plugins` array with the configurations necessary:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// other plugins...
{
@@ -138,7 +138,7 @@ Medusa has a Next.js Starter Template that you can easily use with your Medusa b
In your `.env.local` file (or the file youre using for your environment variables), add the following variable:
```bash title=.env.local
```bash title=".env.local"
NEXT_PUBLIC_PAYPAL_CLIENT_ID=<YOUR_CLIENT_ID>
```
@@ -54,7 +54,7 @@ Next, you need to add configurations for your stripe plugin.
In `medusa-config.js` add the following at the end of the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -145,7 +145,7 @@ Medusa has a Next.js Starter Template that you can easily use with your Medusa b
In your `.env.local` file (or the file youre using for your environment variables), add the following variable:
```bash title=.env.local
```bash title=".env.local"
NEXT_PUBLIC_STRIPE_KEY=<YOUR_PUBLISHABLE_KEY>
```
@@ -92,7 +92,7 @@ Where `<YOUR_APP_ID>` and `<YOUR_ADMIN_API_KEY>` are respectively the Applicatio
Finally, in `medusa-config.js` add the following item into the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -151,7 +151,7 @@ These settings are just examples of what you can pass to the Algolia provider. I
Here's an example of the settings you can use:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -243,7 +243,7 @@ The Next.js Starter Template has the Algolia integration available out of the bo
First, ensure that the search feature is enabled in `store.config.json`:
```json title=store.config.json
```json title="store.config.json"
{
"features": {
"search": true
@@ -263,7 +263,7 @@ Where `<YOUR_APP_ID>` and `<YOUR_SEARCH_API_KEY>` are respectively the Applicati
Finally, change the code in `src/lib/search-client.ts` to the following:
```ts title=src/lib/search-client.ts
```ts title="src/lib/search-client.ts"
import algoliasearch from "algoliasearch/lite"
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || ""
@@ -52,7 +52,7 @@ Where `<YOUR_MEILISEARCH_HOST>` is the host of your MeiliSearch instance. By def
Finally, in `medusa-config.js` add the following item into the `plugins` array:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -76,7 +76,7 @@ const plugins = [
Under the `settings` key of the plugin's options, you can add settings specific to each index. The settings are of the following format:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -117,7 +117,7 @@ These settings are just examples of what you can pass to the MeiliSearch provide
Here's an example of the settings you can use:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...
{
@@ -223,7 +223,7 @@ The Next.js Starter Template has the MeiliSearch integration available out of th
First, ensure that the search feature is enabled in `store.config.json`:
```json title=store.config.json
```json title="store.config.json"
{
"features": {
"search": true
@@ -63,7 +63,7 @@ Where:
Finally, add the plugin to the `plugins` array in `medusa-config.js`:
```js title=medusa-config.js
```js title="medusa-config.js"
const plugins = [
// ...,
{
+2 -2
View File
@@ -271,7 +271,7 @@ Medusa allows you to create custom API Routes exposed as REST APIs.
For example, create the following API Route that allows you to check the customers group and whether it has the `is_b2b` flag enabled:
```ts title=src/api/store/customers/is-b2b/route.ts
```ts title="src/api/store/customers/is-b2b/route.ts"
import type {
CustomerService,
MedusaRequest,
@@ -303,7 +303,7 @@ Medusa allows you to create custom API Routes exposed as REST APIs.
Then add the `requireCustomerAuthentication` middleware in `src/api/middlewares.ts` that ensures only authenticated customer can access this API Route:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import {
requireCustomerAuthentication,
type MiddlewaresConfig,
@@ -105,7 +105,7 @@ Medusa also provides official notification plugins that integrate with third-par
Heres an example of a subscriber that uses the SendGrid plugin to send an email to the customer when the order has a new note:
```ts title=src/subscribers/new-note.ts
```ts title="src/subscribers/new-note.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -190,7 +190,7 @@ You can implement automatic synchronization in Medusa using scheduled jobs. A sc
Heres an example of synchronizing products with a third party service using a [loader](../development/loaders/create.md):
```ts title=src/loaders/sync-products.ts
```ts title="src/loaders/sync-products.ts"
import {
Logger,
ProductService,
@@ -409,7 +409,7 @@ For example, if you're grouping customers with over twenty orders, you can use a
Heres an example of a subscriber that listens to the `order.placed` event and checks if the customer should be added to the VIP customer group based on their number of orders:
```ts title=src/subscribers/add-custom-to-vip.ts
```ts title="src/subscribers/add-custom-to-vip.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -520,7 +520,7 @@ You can alternatively have a Scheduled Job that checks if the number of new prod
Heres an example of listening to the `product.created` event in a subscriber and send a newsletter if the condition is met:
```ts title=src/subscribers/send-products-newsletter.ts
```ts title="src/subscribers/send-products-newsletter.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -142,7 +142,7 @@ For example, if you're selling the Harry Potter movies, you would have a `Produc
To do that, create the file `src/models/product-media.ts` with the following content:
```ts title=src/models/product-media.ts
```ts title="src/models/product-media.ts"
import {
BeforeInsert,
Column,
@@ -272,7 +272,7 @@ Creating an API Route also requires creating a service, which is a class that ty
Before creating the API Routes, youll create the `ProductMediaService`. Create the file `src/services/product-media.ts` with the following content:
```ts title=src/services/product-media.ts
```ts title="src/services/product-media.ts"
import {
FindConfig,
ProductVariantService,
@@ -454,7 +454,7 @@ Creating an API Route also requires creating a service, which is a class that ty
You can now create the API Routes. Create the file `src/api/admin/product-media/route.ts` with the following content:
```ts title=src/api/admin/product-media/route.ts
```ts title="src/api/admin/product-media/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -575,7 +575,7 @@ To add an interface that allows the admin user to upload digital products, you c
You also need to create types for the expected requests and responses of the API Routes you created. This is helpful when using Medusa Reacts custom hooks. To do that, create the file `src/types/product-media.ts` with the following content:
```ts title=src/types/product-media.ts
```ts title="src/types/product-media.ts"
import {
MediaType,
ProductMedia,
@@ -605,7 +605,7 @@ To add an interface that allows the admin user to upload digital products, you c
You can now create your admin UI route. To do that, create the file `src/admin/routes/product-media/page.tsx` with the following content:
```tsx title=src/admin/routes/product-media/page.tsx
```tsx title="src/admin/routes/product-media/page.tsx"
import { RouteConfig } from "@medusajs/admin"
import { DocumentText } from "@medusajs/icons"
import { useAdminCustomQuery } from "medusa-react"
@@ -714,7 +714,7 @@ To add an interface that allows the admin user to upload digital products, you c
In the drawer, you show the Create Digital Product form. To create this form, create the file `src/admin/components/product-media/CreateForm/index.tsx` with the following content:
```tsx title=src/admin/components/product-media/CreateForm/index.tsx
```tsx title="src/admin/components/product-media/CreateForm/index.tsx"
import { useState } from "react"
import { MediaType } from "../../../../models/product-media"
import {
@@ -952,7 +952,7 @@ Finally, you can send a notification, such as an email, to the customer using th
Heres an example of a subscriber that retrieves the download links and sends them to the customer using the SendGrid plugin:
```ts title=src/subscribers/handle-order.ts
```ts title="src/subscribers/handle-order.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
@@ -1055,7 +1055,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
Create the file `src/api/store/product-media/route.ts` with the following content:
```ts title=src/api/store/product-media/route.ts
```ts title="src/api/store/product-media/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -1095,7 +1095,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
First, if you're using TypeScript for your development, create the file `src/types/product-media.ts` with the following content:
```ts title=src/types/product-media.ts
```ts title="src/types/product-media.ts"
import { Product } from "@medusajs/medusa"
import { ProductVariant } from "@medusajs/product"
@@ -1132,7 +1132,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
Then, add in `src/lib/data/index.ts` a new function that retrieves the product media of the product variant being viewed:
```ts title=src/lib/data/index.ts
```ts title="src/lib/data/index.ts"
import {
DigitalProduct,
ProductMedia,
@@ -1165,7 +1165,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
To allow customers to download the file preview without exposing its URL, create a Next.js API route in the file `src/app/api/download/preview/route.ts` with the following content:
```ts title=src/app/api/download/preview/route.ts
```ts title="src/app/api/download/preview/route.ts"
import { NextRequest, NextResponse } from "next/server"
export async function GET(req: NextRequest) {
@@ -1208,7 +1208,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
Next, create the preview button in the file `src/modules/products/components/product-media-preview/index.tsx`:
```tsx title=src/modules/products/components/product-media-preview/index.tsx
```tsx title="src/modules/products/components/product-media-preview/index.tsx"
import Button from "@modules/common/components/button"
import { ProductMedia } from "types/product-media"
@@ -1243,7 +1243,7 @@ To implement this, create a storefront API Route that allows you to fetch the di
Finally, add the button as one of the product actions defined in `src/modules/products/components/product-actions/index.tsx`. These are the actions shown to the customer in the product details page:
```tsx title=src/modules/products/components/product-actions/index.tsx
```tsx title="src/modules/products/components/product-actions/index.tsx"
// other imports...
import ProductMediaPreview from "../product-media-preview"
import { getProductMediaPreviewByVariant } from "@lib/data"
@@ -1315,7 +1315,7 @@ You can change this section to show information relevant to the product. For exa
Next, change the `ProductTabs`, `ProductInfoTab`, and `ShippingInfoTab` components defined in `src/modules/products/components/product-tabs/index.tsx` to the following:
```tsx title=src/modules/products/components/product-tabs/index.tsx
```tsx title="src/modules/products/components/product-tabs/index.tsx"
const ProductTabs = ({ product }: ProductTabsProps) => {
const tabs = useMemo(() => {
return [
@@ -1426,7 +1426,7 @@ When a customer purchases a digital product, the shipping form shown during chec
<!-- eslint-skip -->
```tsx title=src/lib/context/checkout-context.tsx
```tsx title="src/lib/context/checkout-context.tsx"
"use client"
import { medusaClient } from "@lib/config"
@@ -1877,7 +1877,7 @@ When a customer purchases a digital product, the shipping form shown during chec
<!-- eslint-disable max-len -->
```tsx title=src/modules/checkout/components/addresses/index.tsx
```tsx title="src/modules/checkout/components/addresses/index.tsx"
import { useCheckout } from "@lib/context/checkout-context"
import Button from "@modules/common/components/button"
import Spinner from "@modules/common/icons/spinner"
@@ -1949,7 +1949,7 @@ When a customer purchases a digital product, the shipping form shown during chec
Finally, change the shipping details shown in the order confirmation page by replacing the content of `src/modules/order/components/shipping-details/index.tsx` with the following:
```tsx title=src/modules/order/components/shipping-details/index.tsx
```tsx title="src/modules/order/components/shipping-details/index.tsx"
import { Address, ShippingMethod } from "@medusajs/medusa"
type ShippingDetailsProps = {
@@ -2011,7 +2011,7 @@ After the customer purchases the digital product you can show a download button
Create the file `src/api/store/product-media/download/[variant_id]/route.ts` with the following content:
```ts title=src/api/store/product-media/download/route.ts
```ts title="src/api/store/product-media/download/route.ts"
import type {
AbstractFileService,
MedusaRequest,
@@ -2082,7 +2082,7 @@ After the customer purchases the digital product you can show a download button
Then, add the `requireCustomerAuthentication` middleware to this API Route in `src/api/middlewares.ts`:
```ts title=src/api/middlewares.ts
```ts title="src/api/middlewares.ts"
import {
requireCustomerAuthentication,
type MiddlewaresConfig,
@@ -2104,7 +2104,7 @@ After the customer purchases the digital product you can show a download button
To mask the presigned URL, create a Next.js API route at `src/app/api/download/main/[variant_id]/route.ts` with the following content:
```ts title=src/app/api/download/main/[variant_id]/route.ts
```ts title="src/app/api/download/main/[variant_id]/route.ts"
import { NextRequest, NextResponse } from "next/server"
export async function GET(
@@ -2173,7 +2173,7 @@ After the customer purchases the digital product you can show a download button
<!-- eslint-disable max-len -->
```tsx title=src/modules/order/components/items/index.tsx
```tsx title="src/modules/order/components/items/index.tsx"
import useEnrichedLineItems from "@lib/hooks/use-enrich-line-items"
import { LineItem, Region } from "@medusajs/medusa"
import LineItemOptions from "@modules/common/components/line-item-options"
@@ -46,7 +46,7 @@ To associate these entities with the `Store` entity, you need to extend and cust
For example, to associate the `User` entity with the `Store` entity, create the file `src/models/user.ts` with the following content:
```ts title=src/models/user.ts
```ts title="src/models/user.ts"
import {
Column,
Entity,
@@ -73,7 +73,7 @@ To associate these entities with the `Store` entity, you need to extend and cust
Then, you need to extend the `UserRepository` to point to your extended entity. To do that, create the file `src/repositories/user.ts` with the following content:
```ts title=src/repositories/user.ts
```ts title="src/repositories/user.ts"
import { User } from "../models/user"
import {
dataSource,
@@ -102,7 +102,7 @@ To associate these entities with the `Store` entity, you need to extend and cust
This creates a file in the `src/migrations` directory of the format `<TIMESTAMP>_add-user-store-id.ts`. Replace the `up` and `down` methods in that file with the methods here:
```ts title=src/migrations/<TIMESTAMP>_add-user-store-id.ts
```ts title="src/migrations/<TIMESTAMP>_add-user-store-id.ts"
// ...
export class AddUserStoreId1681287255173
@@ -188,7 +188,7 @@ You can also extend services if you need to customize a functionality implemente
<!-- eslint-disable prefer-rest-params -->
```ts title=src/services/user.ts
```ts title="src/services/user.ts"
import { Lifetime } from "awilix"
import {
UserService as MedusaUserService,
@@ -273,7 +273,7 @@ To listen to events, you need to create Subscribers that subscribe a handler fun
To listen to the `order.placed` event, create the file `src/subscribers/orderNotifier.ts` with the following content:
```ts title=src/subscribers/orderNotifier.ts
```ts title="src/subscribers/orderNotifier.ts"
import {
type SubscriberConfig,
type SubscriberArgs,
+1 -1
View File
@@ -99,7 +99,7 @@ To search through product variants by their barcode, you can create a custom API
Heres an example of creating a custom API Route at `/store/pos/search-barcode` that searches product variants by a barcode:
```ts title=src/api/store/pos/search-barcode/route.ts
```ts title="src/api/store/pos/search-barcode/route.ts"
import type {
MedusaRequest,
MedusaResponse,
@@ -172,7 +172,7 @@ To enable the Product Module, first, make sure to set the following environment
Then, enable the `productModule` feature flag in `store.config.json`:
```json title=store.config.json
```json title="store.config.json"
{
"features": {
// other features...
@@ -198,7 +198,7 @@ The Next.js Starter Storefront by default is compatible with MeiliSearch.
To enable or disable the search engine, change the value of the feature in `store.config.json`:
```json title=store.config.json
```json title="store.config.json"
{
"features": {
"search": false
@@ -269,7 +269,7 @@ Where `<YOUR_APP_ID>` and `<YOUR_SEARCH_API_KEY>` are the Algolia App ID and Alg
Next, change the content of `src/lib/search-client.ts` to the following:
```ts title=src/lib/search-client.ts
```ts title="src/lib/search-client.ts"
import algoliasearch from "algoliasearch/lite"
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || ""
@@ -12,7 +12,7 @@ In your `medusa-config.js` , you should ensure that you've configured your CORS
The default configuration uses the following CORS settings:
```js title=medusa-config.js
```js title="medusa-config.js"
// CORS when consuming Medusa from admin
const ADMIN_CORS = process.env.ADMIN_CORS ||
"http://localhost:7000,http://localhost:7001"
@@ -24,4 +24,4 @@ As a last resort to resolve your issue, please try to clear your `npx` cache, as
</TabItem>
</Tabs>
If your issue persists, please try to search through [our GitHub issues](https://github.com/medusajs/medusa/issues) to see if there's a solution for your issue. If not, please [create an issue on GitHub](https://github.com/medusajs/medusa/issues/new?assignees=olivermrbl&labels=status:+needs+triaging,+type:+bug&template=bug_report.md&title=) and our team will help you resolve it soon.
If your issue persists, please try to search through [our GitHub issues](https://github.com/medusajs/medusa/issues) to see if there's a solution for your issue. If not, please [create an issue on GitHub](https://github.com/medusajs/medusa/issues/new?assignees=olivermrbl&labels=status:+needs+triaging,+type:+bug&template=bug_report.md&title=") and our team will help you resolve it soon."

Some files were not shown because too many files have changed in this diff Show More