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
@@ -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,