From 154673f3d889bcccd01032b9f5379d9d71dce607 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 22 May 2024 13:37:48 +0300 Subject: [PATCH] docs: fixes and changes based on latest updates (#7322) * docs: changes based on DX changes * remove fields no longer needed * remove unnecessary parameters * fixes to authenticate middleware usage * add highlight to migrations config * change configuration to http * added missing remote link docs * fix name in sidebar * added notification module docs + updated file module docs * add vale exceptions * fix vale errors * added docs on custom cli scripts --- .../api-routes/cors/page.mdx | 14 +- .../api-routes/protected-routes/page.mdx | 16 +- .../custom-cli-scripts/page.mdx | 78 + .../data-models/common-definitions/page.mdx | 30 +- .../data-models/soft-deletable/page.mdx | 11 +- .../modules/connection-loader/page.mdx | 48 - .../modules/container/page.mdx | 64 +- .../database-operations-in-services/page.mdx | 9 +- .../modules/link-modules/page.mdx | 133 +- .../modules/module-relationships/page.mdx | 50 +- .../modules/remote-link/page.mdx | 198 ++ .../modules/remote-query/page.mdx | 2 +- .../modules/service-factory/page.mdx | 9 - .../book/app/advanced-development/page.mdx | 2 +- .../architectural-modules/page.mdx | 19 +- .../cache-module/page.mdx | 33 - .../event-module/page.mdx | 35 - .../file-module/page.mdx | 35 - www/apps/book/app/basics/data-models/page.mdx | 89 +- .../app/storefront-development/tips/page.mdx | 8 +- www/apps/book/sidebar.mjs | 34 +- .../app/architectural-modules/cache/page.mdx | 18 +- .../app/architectural-modules/event/page.mdx | 18 +- .../app/architectural-modules/file/page.mdx | 18 +- .../architectural-modules/file/s3/page.mdx | 311 ++ .../notification/local/page.mdx | 80 + .../notification/page.mdx | 66 + .../notification/send-notification/page.mdx | 86 + .../notification/sendgrid/page.mdx | 192 ++ .../workflow-engine/page.mdx | 13 + .../commerce-modules/auth/examples/page.mdx | 12 +- .../auth/module-options/page.mdx | 4 +- .../auth/persisting-auth-user/page.mdx | 6 +- .../medusa-application/general/page.mdx | 4 +- www/apps/resources/app/medusa-cli/page.mdx | 56 + .../create-medusa-app-errors/forwarding.mdx | 2 +- .../_sections/database-errors/docker.mdx | 2 +- www/apps/resources/generated/files-map.mjs | 36 +- www/apps/resources/generated/sidebar.mjs | 52 + www/apps/resources/generated/slug-changes.mjs | 6 +- .../file.AbstractFileProviderService/page.mdx | 33 +- .../references/modules/notification/page.mdx | 7 +- .../page.mdx | 103 + .../page.mdx | 287 -- .../page.mdx | 224 -- .../notification.ReturnedData/page.mdx | 9 - .../page.mdx | 4 +- .../order.UpdateOrderTaxLineDTO/page.mdx | 4 +- www/apps/resources/sidebar.mjs | 33 + .../generated/typedoc-json-output/file.json | 116 +- .../typedoc-json-output/notification.json | 2583 +---------------- .../src/constants/custom-options.ts | 5 +- .../constants/merger-custom-options/file.ts | 33 +- .../merger-custom-options/notification.ts | 120 +- www/vale/styles/docs/ModuleNames.yml | 5 +- 55 files changed, 1674 insertions(+), 3791 deletions(-) create mode 100644 www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx delete mode 100644 www/apps/book/app/advanced-development/modules/connection-loader/page.mdx create mode 100644 www/apps/book/app/advanced-development/modules/remote-link/page.mdx delete mode 100644 www/apps/book/app/architectural-concepts/cache-module/page.mdx delete mode 100644 www/apps/book/app/architectural-concepts/event-module/page.mdx delete mode 100644 www/apps/book/app/architectural-concepts/file-module/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/file/s3/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/notification/local/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/notification/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx create mode 100644 www/apps/resources/app/architectural-modules/workflow-engine/page.mdx create mode 100644 www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx delete mode 100644 www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx delete mode 100644 www/apps/resources/references/notification/interfaces/notification.INotificationService/page.mdx delete mode 100644 www/apps/resources/references/notification/interfaces/notification.ReturnedData/page.mdx diff --git a/www/apps/book/app/advanced-development/api-routes/cors/page.mdx b/www/apps/book/app/advanced-development/api-routes/cors/page.mdx index 2ca6ba8fd4..633b1a9635 100644 --- a/www/apps/book/app/advanced-development/api-routes/cors/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/cors/page.mdx @@ -12,16 +12,18 @@ Cross-Origin Resource Sharing (CORS) allows only configured origins to access yo ### CORS Configurations -You configure allowed origins for Store and Admin API Routes using the `store_cors` and `admin_cors` configurations in `medusa-config.js`. Each of these configurations accepts a URL pattern to identify allowed origins. +You configure allowed origins for Store and Admin API Routes using the `storeCors` and `adminCors` properties of the `http` configuration in `medusa-config.js`. Each of these configurations accepts a URL pattern to identify allowed origins. For example: ```js title="medusa-config.js" module.exports = { projectConfig: { - admin_cors: "http://localhost:7001", - store_cors: "http://localhost:8000", - // ... + http: { + adminCors: "http://localhost:7001", + storeCors: "http://localhost:8000", + // ... + } }, // ... } @@ -90,7 +92,7 @@ export const config: MiddlewaresConfig = { return cors({ origin: parseCorsOrigins( - configModule.projectConfig.store_cors + configModule.projectConfig.http.storeCors ), credentials: true, })(req, res, next) @@ -101,4 +103,4 @@ export const config: MiddlewaresConfig = { } ``` -This retrieves the configurations exported from `medusa-config.js` and applies the `store_cors` to routes starting with `/custom`. +This retrieves the configurations exported from `medusa-config.js` and applies the `storeCors` to routes starting with `/custom`. diff --git a/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx b/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx index 7ef4562a28..cafe2e69e8 100644 --- a/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx @@ -59,21 +59,21 @@ For example: ```ts title="src/api/store/me/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]} import type { - MedusaRequest, + AuthenticatedMedusaRequest, MedusaResponse, } from "@medusajs/medusa" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { ICustomerModuleService } from "@medusajs/types" export const GET = async ( - req: MedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const customerService: ICustomerModuleService = req.scope.resolve(ModuleRegistrationName.CUSTOMER) const customer = await customerService.retrieve( - req.user.customer_id + req.auth.actor_id ) // ... @@ -92,21 +92,21 @@ For example: ```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]} import type { - MedusaRequest, + AuthenticatedMedusaRequest, MedusaResponse, } from "@medusajs/medusa" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { IUserModuleService } from "@medusajs/types" export const GET = async ( - req: MedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const userService: IUserModuleService = req.scope.resolve( ModuleRegistrationName.USER ) - const user = await userService.retrieve(req.user.userId) + const user = await userService.retrieve(req.auth.actor_id) // ... } @@ -129,9 +129,7 @@ export const highlights = [ ```ts title="src/api/middlewares.ts" highlights={highlights} // TODO update import -import { - authenticate, -} from "@medusajs/medusa/dist/utils/authenticate-middleware" +import { MiddlewaresConfig, authenticate } from "@medusajs/medusa" export const config: MiddlewaresConfig = { routes: [ diff --git a/www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx b/www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx new file mode 100644 index 0000000000..70218a8cf3 --- /dev/null +++ b/www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx @@ -0,0 +1,78 @@ +export const metadata = { + title: `${pageNumber} Custom CLI Scripts`, +} + +# {metadata.title} + +In this chapter, you'll learn how create and execute custom scripts from Medusa's CLI tool. + +## What is a Custom CLI Script? + +A custom CLI script is a function to execute through Medusa's CLI tool. This is useful when creating custom Medusa tooling to run as a CLI tool. + +--- + +## How to Create a Custom CLI Script? + +To create a custom CLI script, create a TypeScript or JavaScript file under the `src/scripts` directory. The file must default export a function. + +For example, create the file `src/scripts/my-script.ts` with the following content: + +```ts title="src/scripts/my-script.ts" +import { + ExecArgs, + IProductModuleService +} from "@medusajs/types" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" + +export default async function myScript ({ + container +}: ExecArgs) { + const productModuleService: IProductModuleService = + container.resolve(ModuleRegistrationName.PRODUCT) + + const [, count] = await productModuleService.listAndCount() + + console.log(`You have ${count} product(s)`) +} +``` + +The function receives as a parameter an object having a `container` property, which is an instance of the Medusa Container. Use it to resolve resources in your Medusa application. + +--- + +## How to Run Custom CLI Script? + +To run the custom CLI script, `build` your code then run the `exec` command: + +```bash npm2yarn +npm run build +npx medusa exec ./dist/scripts/my-script.js +``` + +Notice that you pass the path to the file in the `dist` directory. + +--- + +## Custom CLI Script Arguments + +Your script can accept arguments from the command line. Arguments are passed to the function's object parameter in the `args` property. + +For example: + +```ts +import { ExecArgs } from "@medusajs/types" + +export default async function myScript ({ + args +}: ExecArgs) { + console.log(`The arguments you passed: ${args}`) +} +``` + +Then, pass the arguments in the `exec` command after the file path: + +```bash npm2yarn +npm run build +npx medusa exec ./dist/scripts/my-script.js arg1 arg2 +``` \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx b/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx index cf440d39cf..82595bf89d 100644 --- a/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx @@ -37,17 +37,14 @@ The following example showcase a data model with common definitions: ```ts import { - BeforeCreate, Entity, Enum, OneToOne, PrimaryKey, Property, } from "@mikro-orm/core" -import { - createPsqlIndexStatementHelper, - generateEntityId, -} from "@medusajs/utils" +import { BaseEntity } from "@medusajs/utils" +// assuming this is another implemented data model import ProductVariant from "./product-variant" export enum MediaType { @@ -55,14 +52,8 @@ export enum MediaType { PREVIEW = "preview" } -const VariantIdIndex = createPsqlIndexStatementHelper({ - name: "IDX_product_media_variant_id", - tableName: "product_media", - columns: "variant_id", -}).MikroORMIndex - @Entity() -export default class ProductMedia { +class ProductMedia extends BaseEntity { @PrimaryKey({ columnType: "text" }) id: string @@ -78,7 +69,6 @@ export default class ProductMedia { @Property({ columnType: "text" }) mime_type: string - @VariantIdIndex() @Property({ columnType: "text" }) variant_id: string @@ -87,21 +77,13 @@ export default class ProductMedia { onDelete: "cascade", }) variant: ProductVariant - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "promed") - } - - @OnInit() - OnInit() { - this.id = generateEntityId(this.id, "promed") - } } + +export default ProductMedia ``` In the example above: - The `ProductMedia` data model has the columns `id`, `name`, `type`, `file_key`, `mime_type`, and `variant_id`. - The data model has an index on the `variant_id` column. -- The data model has a one-to-one relation to the `ProductVariant` data model. +- The data model has a one-to-one relation to a `ProductVariant` data model. diff --git a/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx b/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx index 183b718dda..dabf237728 100644 --- a/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx @@ -20,25 +20,28 @@ When retrieving or listing records of that data model, records having their `del To create a soft-deletable model, first, add the following filter decorator to the data model class: -```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["6"]]} +```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["7"]]} // other imports... import { Entity, Filter } from "@mikro-orm/core" import { DALUtils } from "@medusajs/utils" +import { BaseEntity } from "@medusajs/utils" @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) -export default class MySoftDeletable { +class MySoftDeletable extends BaseEntity { // ... } + +export default MySoftDeletable ``` Then, add a `deleted_at` field to the data model: -```ts highlights={[["4"], ["5"]]} +```ts highlights={[["7"], ["8"]]} // other imports... import { Property } from "@mikro-orm/core" -export default class MySoftDeletable { +class MySoftDeletable extends BaseEntity { // ... @Property({ columnType: "timestamptz", nullable: true }) diff --git a/www/apps/book/app/advanced-development/modules/connection-loader/page.mdx b/www/apps/book/app/advanced-development/modules/connection-loader/page.mdx deleted file mode 100644 index 7204190b89..0000000000 --- a/www/apps/book/app/advanced-development/modules/connection-loader/page.mdx +++ /dev/null @@ -1,48 +0,0 @@ -export const metadata = { - title: `${pageNumber} Database Connection Loader`, -} - -# {metadata.title} - -In this document, you’ll learn about how to load the database connection in your module. - -## How to Add a Database Connection Loader? - -To ensure that your module's database operations use the Medusa application's database connection, export a database connection loader in your module's definition. - -Medusa provides a utility function that creates the database connection loader for you. - -For example: - -```ts title="src/modules/hello/index.ts" -// other imports... -import { ModulesSdkUtils } from "@medusajs/utils" -import { MyCustom } from "./models/my-custom" - -const pathToMigrations = __dirname + "/migrations" - -// ... - -const connectionLoader = ModulesSdkUtils - .mikroOrmConnectionLoaderFactory({ - moduleName, - moduleModels: [MyCustom], - migrationsPath: pathToMigrations, - }) - -export default { - // ... - loaders: [ - // ... - connectionLoader, - ], -} -``` - -The `mikroOrmConnectionLoaderFactory` function accepts an object with the following properties: - -- `moduleName`: The name of the module. -- `moduleModules`: An array of data models in the module. -- `migrationsPath`: The path to the migrations file. - -You can now implement data-management methods as explained in the next chapters. diff --git a/www/apps/book/app/advanced-development/modules/container/page.mdx b/www/apps/book/app/advanced-development/modules/container/page.mdx index c8aa9ec6e3..923f727790 100644 --- a/www/apps/book/app/advanced-development/modules/container/page.mdx +++ b/www/apps/book/app/advanced-development/modules/container/page.mdx @@ -14,63 +14,12 @@ So, resources in the module, such as services or loaders, can only resolve other --- -## The Container Loader +## Resources Registered in the Module's Container -Medusa provides a utility function that creates a container loader. This loader takes care of registering resources in your container. +Some resources registered in the module's container are: -For example: - -export const highlights = [ - ["11", "moduleContainerLoaderFactory", "Create the container loader."], - ["25", "", "Export the container loader."] -] - -```ts title="src/modules/hello/index.ts" highlights={highlights} -// other imports... -import HelloModuleService from "./service" -import { MyCustom } from "./models/my-custom" -import { - ModulesSdkUtils, - MikroOrmBaseRepository, -} from "@medusajs/utils" - -// ... - -const containerLoader = ModulesSdkUtils.moduleContainerLoaderFactory({ - moduleModels: { - MyCustom, - }, - moduleRepositories: { - BaseRepository: MikroOrmBaseRepository, - }, - moduleServices: { - HelloModuleService, - }, -}) - -export default { - // ... - loaders: [containerLoader], -} -``` - -You create the container loader using the utility function `moduleContainerLoaderFactory` and export it in the module's definition. - -### moduleContainerLoaderFactory Parameters - -The `moduleContainerLoaderFactory` function accepts as a parameter an object with the following properties: - -- `moduleModels`: An object where each key is a data model's name, and its value the data model class. -- `moduleRepositories`: An object of the module's repositories. You import here the `MikroOrmBaseRepository` from `@medusajs/utils` and use it as the value of `BaseRepository`. -- `moduleServices`: An object where each key is the service's registration name, and its value is the service class. - -### Resources Registered by the Container Loader - -The container loader registers in the module's container: - -- The services passed in the `moduleServices` property. -- The repositories provided in the `moduleRepositories`. -- A generated service for each data model provided in `moduleModels`. +- The module's main service. +- A generated service for each data model in your module. The registration name is the camel-case data model name suffixed by `Service`. For example, `myCustomService`. ![Example of registered resources in the container](https://res.cloudinary.com/dza7lstvk/image/upload/v1714400573/Medusa%20Book/modules-container_mkcbaq.jpg) @@ -84,7 +33,7 @@ A service's constructor accepts as a first parameter an object used to resolve r For example: -```ts +```ts highlights={[["5"], ["12"]]} import { ModulesSdkTypes } from "@medusajs/types" import { MyCustom } from "./models/my-custom" @@ -109,12 +58,11 @@ A loader function in a module accepts as a parameter an object having the proper For example: -```ts +```ts highlights={[["8"]]} import { LoaderOptions, } from "@medusajs/modules-sdk" - export default function helloWorldLoader({ container, }: LoaderOptions) { diff --git a/www/apps/book/app/advanced-development/modules/database-operations-in-services/page.mdx b/www/apps/book/app/advanced-development/modules/database-operations-in-services/page.mdx index 897befcb5a..388eccd2a1 100644 --- a/www/apps/book/app/advanced-development/modules/database-operations-in-services/page.mdx +++ b/www/apps/book/app/advanced-development/modules/database-operations-in-services/page.mdx @@ -6,14 +6,14 @@ export const metadata = { In this document, you’ll learn how to implement database operations, such as creating a record, in the main service. -## Use Data Model Services +## Use the Data Model's Generated Service -The module container has a generated service registered for each data model. You can resolve that service and use it to perform database operations on the data model. +To perform database operations on a data model, use the model's generated service in the module's container. For example: export const highlights = [ - ["13", "", "Inject myCustomService, which is the service generated by the container loader for the MyCustom data model."], + ["13", "", "Inject myCustomService, which is the generated service of the `MyCustom` data model."], ["22", "", "Add a new field for the generated service of the MyCustom data model."], ["29", "", "Set the class field to the injected dependency."], ["35", "create", "Use the `create` method of the generated service."] @@ -55,8 +55,7 @@ class HelloModuleService extends ModulesSdkUtils data: CreateMyCustomDTO ): Promise { const myCustom = await this.myCustomService_.create( - data, - context + data ) return myCustom diff --git a/www/apps/book/app/advanced-development/modules/link-modules/page.mdx b/www/apps/book/app/advanced-development/modules/link-modules/page.mdx index f8ad859e1b..934cf2dba3 100644 --- a/www/apps/book/app/advanced-development/modules/link-modules/page.mdx +++ b/www/apps/book/app/advanced-development/modules/link-modules/page.mdx @@ -10,137 +10,14 @@ In this chapter, you’ll learn what a link module is and how to use the remote A link module is a module whose only purpose is to define a relationship between two modules’ data models. The relationship is represented as a pivot or link table in the database, pointing at the primary keys of each data model. -For example, Medusa defines a link module between the Product and Pricing modules. The link module builds a relationship between the `ProductVariant` data model and the `PriceSet` data model. +For example, Medusa has a link module that defines a relationship between the Product and Pricing modules. It links the `ProductVariant` and `PriceSet` data models. ![Diagram showcasing the link module between the Product and Pricing modules](https://res.cloudinary.com/dza7lstvk/image/upload/v1709651569/Medusa%20Resources/product-pricing_vlxsiq.jpg) -Link modules provide more flexibility in managing relationships between modules while maintaining module isolation. +Link modules provide more flexibility in managing relationships between modules while maintaining module isolation. The Medusa application only creates the link tables when both modules are available. -Link modules are currently only available for Medusa’s commerce modules. The Medusa application only creates the link tables when both modules are available. + ---- +Link modules are currently only available for Medusa’s commerce modules. -## What is the Remote Link? - -The remote link is a class with utility methods to manage links between modules. It’s registered in the Medusa container under the `remoteLink` registration name. - -For example: - -```ts -import { - MedusaRequest, - MedusaResponse, -} from "@medusajs/medusa" -import { - ModuleRegistrationName, - RemoteLink, -} from "@medusajs/modules-sdk" -import { - ContainerRegistrationKeys, -} from "@medusajs/utils" - -export async function POST( - req: MedusaRequest, - res: MedusaResponse -): Promise { - const remoteLink: RemoteLink = req.scope.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // ... -} -``` - -You can use its methods to manage links, such as create or delete links. - -### Create Link - -To create a link between records of two data models, use the `create` method of the remote link. - -For example: - -```ts -import { Modules } from "@medusajs/utils" - -// ... - -await remoteLink.create({ - [Modules.PRODUCT]: { - variant_id: product.variants[0].id, - }, - [Modules.PRICING]: { - price_set_id: price.id, - }, -}) -``` - -The `create` method accepts as a parameter an object. The object’s keys are the names of the linked modules. - -The value of each module’s property is an object. It defines the values of the linked fields. - -So, in the example above, you specify for the Product Module the value of the `variant_id`, and for the Pricing Module the value of `price_set_id`. These are the fields linked between the models of the two modules. - -### Dismiss Link - -To remove a link between records of two data models, use the `dismiss` method of the remote link. This doesn’t remove the records, only the relation between them. - -For example: - -```ts -import { Modules } from "@medusajs/utils" - -// ... - -await remoteLink.dismiss({ - [Modules.PRODUCT]: { - variant_id: product.variants[0].id, - }, - [Modules.PRICING]: { - price_set_id: price.id, - }, -}) -``` - -The `dismiss` method accepts the same parameter type as the [create method](#create-link). - -### Cascade Delete Linked Records - -If a record, such as a variant, is deleted, use the `delete` method of the remote link to delete all associated links with cascade delete enabled. - -For example: - -```ts -import { Modules } from "@medusajs/utils" - -// ... - -await productModuleService.deleteVariants([variant.id]) - -await remoteLink.delete({ - [Modules.PRODUCT]: { - variant_id: variant.id, - }, -}) -``` - -This deletes all records linked to the deleted variant with cascade delete enabled in their relationship. - -### Restore Linked Records - -If a record, such as a variant, that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all associated links that were cascade deleted. - -For example: - -```ts -import { Modules } from "@medusajs/utils" - -// ... - -await productModuleService.restoreVariants([variant.id]) - -await remoteLink.restore({ - [Modules.PRODUCT]: { - variant_id: variant.id, - }, -}) -``` + diff --git a/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx b/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx index 120a2a869f..ee292bb56d 100644 --- a/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx +++ b/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx @@ -40,18 +40,16 @@ The Medusa application resolves these relationships while maintaining isolation Consider you’re creating a data model that adds custom fields associated with a product: -```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["19"]]} -import { generateEntityId } from "@medusajs/utils" +```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]} +import { BaseEntity } from "@medusajs/utils" import { - BeforeCreate, Entity, - OnInit, PrimaryKey, Property, } from "@mikro-orm/core" @Entity() -export class CustomProductData { +export class CustomProductData extends BaseEntity { @PrimaryKey({ columnType: "text" }) id!: string @@ -60,16 +58,6 @@ export class CustomProductData { @Property({ columnType: "text", nullable: true }) product_id?: string - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "cpd") - } - - @OnInit() - OnInit() { - this.id = generateEntityId(this.id, "cpd") - } } ``` @@ -81,7 +69,6 @@ When you add a new data model, make sure to: - [Create a migration for it.](../../../basics/data-models/page.mdx#create-a-migration) - [Add it to the second parameter of the main service's factory function.](../service-factory/page.mdx#abstractModuleServiceFactory-parameters) -- Add it to the [container](../container/page.mdx) and [connection](../connection-loader/page.mdx) loaders. @@ -115,7 +102,6 @@ class HelloModuleService extends ModulesSdkUtils __joinerConfig(): ModuleJoinerConfig { return { serviceName: "helloModuleService", - primaryKeys: ["id"], alias: [ { name: ["my_custom"], @@ -159,12 +145,6 @@ This creates a relationship to the `Product` data model of the Product Module us optional: false, description: "The name of your module (as added in `medusa-config.js`)." }, - { - name: "primaryKeys", - type: "`string[]`", - optional: false, - description: "The primary key field names used in your module's data models.", - }, { name: "alias", type: "`object[]`", @@ -240,8 +220,6 @@ const modules = { helloModuleService: { // ... definition: { - key: "helloModuleService", - registrationName: "helloModuleService", isQueryable: true, }, }, @@ -251,28 +229,6 @@ const modules = { Enabling the `isQueryable` property is required to use relationships in a module. -The `definition` property’s value is an object that accepts the following properties, among others: - - - --- ## Reference Inner Data Models diff --git a/www/apps/book/app/advanced-development/modules/remote-link/page.mdx b/www/apps/book/app/advanced-development/modules/remote-link/page.mdx new file mode 100644 index 0000000000..04b9f6bfdf --- /dev/null +++ b/www/apps/book/app/advanced-development/modules/remote-link/page.mdx @@ -0,0 +1,198 @@ +export const metadata = { + title: `${pageNumber} Remote Link`, +} + +# {metadata.title} + +In this chapter, you’ll learn what the remote link is and how to use it to manage links. + +## What is the Remote Link? + +The remote link is a class with utility methods to manage links defined by the link module. It’s registered in the Medusa container under the `remoteLink` registration name. + +For example: + +```ts +import { + MedusaRequest, + MedusaResponse, +} from "@medusajs/medusa" +import { + ModuleRegistrationName, + RemoteLink, +} from "@medusajs/modules-sdk" +import { + ContainerRegistrationKeys, +} from "@medusajs/utils" + +export async function POST( + req: MedusaRequest, + res: MedusaResponse +): Promise { + const remoteLink: RemoteLink = req.scope.resolve( + ContainerRegistrationKeys.REMOTE_LINK + ) + + // ... +} +``` + +You can use its methods to manage links, such as create or delete links. + +### Create Link + +To create a link between records of two data models, use the `create` method of the remote link. + +For example: + +```ts +import { Modules } from "@medusajs/utils" + +// ... + +await remoteLink.create({ + [Modules.PRODUCT]: { + variant_id: product.variants[0].id, + }, + [Modules.PRICING]: { + price_set_id: price.id, + }, +}) +``` + +The `create` method accepts as a parameter an object. The object’s keys are the names of the linked modules. + +The value of each module’s property is an object. It defines the values of the linked fields. + +So, in the example above, you specify for the Product Module the value of the `variant_id`, and for the Pricing Module the value of `price_set_id`. These are the fields linked between the models of the two modules. + +### Dismiss Link + +To remove a link between records of two data models, use the `dismiss` method of the remote link. This doesn’t remove the records, only the relation between them. + +For example: + +```ts +import { Modules } from "@medusajs/utils" + +// ... + +await remoteLink.dismiss({ + [Modules.PRODUCT]: { + variant_id: product.variants[0].id, + }, + [Modules.PRICING]: { + price_set_id: price.id, + }, +}) +``` + +The `dismiss` method accepts the same parameter type as the [create method](#create-link). + +### Cascade Delete Linked Records + +If a record, such as a variant, is deleted, use the `delete` method of the remote link to delete all associated links with cascade delete enabled. + +For example: + +```ts +import { Modules } from "@medusajs/utils" + +// ... + +await productModuleService.deleteVariants([variant.id]) + +await remoteLink.delete({ + [Modules.PRODUCT]: { + variant_id: variant.id, + }, +}) +``` + +This deletes all records linked to the deleted variant with cascade delete enabled in their relationship. + +### Restore Linked Records + +If a record, such as a variant, that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all associated links that were cascade deleted. + +For example: + +```ts +import { Modules } from "@medusajs/utils" + +// ... + +await productModuleService.restoreVariants([variant.id]) + +await remoteLink.restore({ + [Modules.PRODUCT]: { + variant_id: variant.id, + }, +}) +``` + +--- + +## Link Module's Service + +The remote link has a `getLinkModule` method to retrieve the service of the link module. This service has `list` and `retrieve` methods to retrieve the linked items. + +For example, to retrieve the link module of the Product and Pricing modules: + +export const linkModuleServiceHighlights = [ + ["6", "Modules.PRODUCT", "The name of the first module in the link module's definition."], + ["7", '"variant_id"', "The foreign key that links to the record in the first module."], + ["8", "Modules.PRICING", "The name of the second module in the link module's definition."], + ["9", '"price_set_id"', "The foreign key that links to the record in the second module."], + ["12", "", "The link module's service is undefined if either of the modules isn't installed or there's no link module with the specified definition."] +] + +```ts highlights={linkModuleServiceHighlights} +import { Modules } from "@medusajs/utils" + +// ... + +const linkModuleService = remoteLink.getLinkModule( + Modules.PRODUCT, + "variant_id", + Modules.PRICING, + "price_set_id" +) + +if (!linkModuleService) { + return +} +``` + +The `getLinkModule` method accepts four parameter: + +1. A string indicating the name of the first module in the link module's definition. +2. A string indicating the foreign key that links to the record in the first module. +3. A string indicating the name of the second module in the link module's definition. +4. A string indicating the foreign key that links to the record in the second module. + +Notice that the returned link module service might be undefined if either of the modules isn't installed, or if there's no link module with the specified definition. + +### List Linked Items + +The link module's service has a `list` method that retrieves a list of linked records. It also accepts filters to retrieve specific linked items. + +For example, to retrieve the price sets linked to a variant: + +```ts +import { Modules } from "@medusajs/utils" + +// ... + +const linkModuleService = remoteLink.getLinkModule( + Modules.PRODUCT, + "variant_id", + Modules.PRICING, + "price_set_id" +) + +const items = await linkModuleService.list( + { variant_id: [variant.id] }, + { select: ["variant_id", "price_set_id"] } +) +``` diff --git a/www/apps/book/app/advanced-development/modules/remote-query/page.mdx b/www/apps/book/app/advanced-development/modules/remote-query/page.mdx index 37aa337f50..f489ead610 100644 --- a/www/apps/book/app/advanced-development/modules/remote-query/page.mdx +++ b/www/apps/book/app/advanced-development/modules/remote-query/page.mdx @@ -114,7 +114,7 @@ The `remoteQueryObjectFromString` function accepts a `variables` property. You c ## Sort Records -```ts highlights={[["4"], ["5"], ["6"]]} +```ts highlights={[["5"], ["6"], ["7"]]} const query = remoteQueryObjectFromString({ entryPoint: "custom_product_data", fields: ["id", "custom_field", "product.title"], diff --git a/www/apps/book/app/advanced-development/modules/service-factory/page.mdx b/www/apps/book/app/advanced-development/modules/service-factory/page.mdx index 8a8b294104..54ff92147b 100644 --- a/www/apps/book/app/advanced-development/modules/service-factory/page.mdx +++ b/www/apps/book/app/advanced-development/modules/service-factory/page.mdx @@ -22,15 +22,6 @@ Medusa provides a service factory that your module’s main service can extend. ## How to Extend the Service Factory? - - -Your module must be using the following loaders from the previous chapters: - -- [Container Loader](../container/page.mdx). -- [Connection Loader](../connection-loader/page.mdx). - - - Medusa provides the service factory as a function your service extends. The function creates and returns a service class with generated data-management methods. For example, create the file `src/modules/hello/service.ts` with the following content: diff --git a/www/apps/book/app/advanced-development/page.mdx b/www/apps/book/app/advanced-development/page.mdx index cd3890d946..d26956763e 100644 --- a/www/apps/book/app/advanced-development/page.mdx +++ b/www/apps/book/app/advanced-development/page.mdx @@ -9,9 +9,9 @@ In the previous chapters, you got a brief introduction to Medusa’s basic conce The next chapters dive deeper into each concept. By the end of these chapters, you’ll be able to: - Expose API routes with control over authentication, parsing request bodies, and more. -- Create data models with complex fields and relations. - Manage data models in services. - Create relationships between modules. +- Create data models with complex fields and relations. - Create loaders outside of modules. - Access events payloads. - Create advanced workflows and configure retries and timeout. diff --git a/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx b/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx index 3f15357b4d..7039edcaeb 100644 --- a/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx +++ b/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx @@ -12,16 +12,21 @@ An architectural module implements features and mechanisms related to the Medusa Since modules are interchangeable, you have more control over Medusa’s architecture. For example, you can choose to use Memcached for event handling instead of Redis. - +--- -Refer to the [Architectural Modules reference](!resources!/architectural-modules) for a list of Medusa’s architectural modules. +### Architectural Module Type - +There are different architectural module types including: + +![Diagram illustrating how the modules connect to third-party services](https://res.cloudinary.com/dza7lstvk/image/upload/v1716197340/Medusa%20Book/architectural-modules_bj9bb9.jpg) + +- Cache Module: Defines the caching mechanism or logic to cache computational results. +- Event Module: Integrates a pub/sub service to handle subscribing to and emitting events. +- File Module: Integrates a storage service to handle uploading files. +- Notification Module: Integrates a third-party service or defines custom logic to send notifications to users and customers. --- -## How to Create an Architectural Module? +## Architectural Modules List -You create an architectural module like you’ve been creating custom modules: create a module with a service and export that service in the module’s definition file. The module's service extends an abstract class or interface provided by Medusa with predefined method signatures. - -The next chapters explain the different architectural module types and how to create an architectural module for each. +Refer to the [Architectural Modules reference](!resources!/architectural-modules) for a list of Medusa’s architectural modules, available modules to install, and how to create an architectural module. diff --git a/www/apps/book/app/architectural-concepts/cache-module/page.mdx b/www/apps/book/app/architectural-concepts/cache-module/page.mdx deleted file mode 100644 index ca6b02ea7e..0000000000 --- a/www/apps/book/app/architectural-concepts/cache-module/page.mdx +++ /dev/null @@ -1,33 +0,0 @@ -export const metadata = { - title: `${pageNumber} Cache Module`, -} - -# {metadata.title} - -In this chapter, you’ll learn about what the Cache Module is. - -## What is a Cache Module? - -A Cache Module is used to cache the results of computations such as price selection or various tax calculations. - -The underlying database, third-party service, or caching logic is flexible since it's implemented in a module. You can choose from Medusa’s cache modules or create your own to support something more suitable for your architecture. - ---- - -## Default Cache Module - -By default, Medusa uses the In-Memory Cache Module. This module uses a plain JavaScript Map object to store the cache data. - -This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the [Redis Cache Module](!resources!/architectural-modules/cache/redis). - ---- - -## List of Cache Modules - -Refer to the Medusa Learning Resources for a [list of available cache modules](!resources!/architectural-modules/cache). - ---- - -## Create a Cache Module - -To create a cache module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/cache/create). diff --git a/www/apps/book/app/architectural-concepts/event-module/page.mdx b/www/apps/book/app/architectural-concepts/event-module/page.mdx deleted file mode 100644 index 2ca511da14..0000000000 --- a/www/apps/book/app/architectural-concepts/event-module/page.mdx +++ /dev/null @@ -1,35 +0,0 @@ -export const metadata = { - title: `${pageNumber} Event Module`, -} - -# {metadata.title} - -In this chapter, you’ll learn about what the Event Module is. - -## What is an Event Module? - -In previous chapters, you learned that the Medusa application emits events, and subscribers handle those events. - -The Event Module implements the underlying publish/subscribe system that handles queueing events, emitting them, and executing their subscribers. - -This makes the event architecture customizable, as you can either choose one of Medusa’s event modules or create your own. - ---- - -## Default Event Module - -By default, Medusa uses the Local Event Module. This module uses Node’s EventEmitter to implement the publish/subscribe system. - -This is useful for development. However, for production, it’s highly recommended to use other Event Modules, such as the [Redis Event Module](!resources!/architectural-modules/event/redis). - ---- - -## List of Event Modules - -Refer to the Medusa Learning Resources for a [list of available event modules](!resources!/architectural-modules/event). - ---- - -## Create a Event Module - -To create an event module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/event/create). diff --git a/www/apps/book/app/architectural-concepts/file-module/page.mdx b/www/apps/book/app/architectural-concepts/file-module/page.mdx deleted file mode 100644 index 23ad9ac077..0000000000 --- a/www/apps/book/app/architectural-concepts/file-module/page.mdx +++ /dev/null @@ -1,35 +0,0 @@ -export const metadata = { - title: `${pageNumber} File Module`, -} - -# {metadata.title} - -In this chapter, you’ll learn about what the File Module is. - -## What is the File Module? - -The File Module exposes the functionalities to upload assets, such as product images, to the Medusa application. - ---- - -## What is a File Provider Module? - -A file provider module implements the logic of handling uploads and downloads. The File Module must have one file provider module configured. - -By default, Medusa uses the Local File Module. This module uploads files to the `uploads` directory of your Medusa application. - -{/* TODO add once s3 module is working/published? */} - -{/* This is useful for development. However, for production, it’s highly recommended to use other File Modules, such as the [S3 Module](!resources!/architectural-modules/event/redis). */} - ---- - -## List of File Provider Modules - -Refer to the Medusa Learning Resources for a [list of available file provider modules](!resources!/architectural-modules/file). - ---- - -## Create a File Provider Module - -To create a file provider module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/references/file-provider-module). diff --git a/www/apps/book/app/basics/data-models/page.mdx b/www/apps/book/app/basics/data-models/page.mdx index 3c2b6187db..43eeb2d997 100644 --- a/www/apps/book/app/basics/data-models/page.mdx +++ b/www/apps/book/app/basics/data-models/page.mdx @@ -30,44 +30,24 @@ A data model is a class created in a TypeScript or JavaScript file under a modul For example, create the file `src/modules/hello/models/my-custom.ts` with the following content: ```ts title="src/modules/hello/models/my-custom.ts" -import { generateEntityId } from "@medusajs/utils" +import { BaseEntity } from "@medusajs/utils" import { - BeforeCreate, Entity, - OnInit, PrimaryKey, Property, } from "@mikro-orm/core" @Entity() -export class MyCustom { +export class MyCustom extends BaseEntity { @PrimaryKey({ columnType: "text" }) id!: string @Property({ columnType: "text" }) name: string - - @BeforeCreate() - onCreate() { - this.id = generateEntityId(this.id, "mc") - } - - @OnInit() - OnInit() { - this.id = generateEntityId(this.id, "mc") - } } ``` -This defines a new data model `MyCustom` with the fields `id` and `name`. - -The `onCreate` method generates an ID for the data model's record when it's created. The `onInit` method sets the ID when the record is loaded. - - - -The `generateEntityId` utility method prefixes the `id` of a record with the string provided in the second parameter. This follows Medusa's conventions of creating IDs. - - +This defines a new data model `MyCustom` with the fields `id` and `name`. Data models extend the `BaseEntity` class imported from `@medusajs/utils`. ### Create a Migration @@ -80,8 +60,7 @@ A migration is a class created in a TypeScript or JavaScript file under a module 1. Create the file `src/modules/hello/mikro-orm.config.dev.ts` with the following content: - ```ts - import "dotenv/config" + ```ts highlights={[["8", "hello", "The module's name."]]} import path from "path" import { TSMigrationGenerator } from "@medusajs/utils" import { MyCustom } from "./models/my-custom" @@ -140,66 +119,6 @@ The queries performed in each of the methods use PostgreSQL syntax. -### Add Migration to Module Definition - -After creating the migration, you must add it to your module's definition. - -To add a module's migrations to its definitions, use the `ModulesSdkUtils` utility functions imported from `@medusajs/utils`. It has functions to create and define the migration scripts in your module definition. - -Change the content of `src/modules/hello.index.ts` that you created in a [previous chapter](../modules-and-services/page.mdx) to the following: - -```ts title="src/modules/hello.index.ts" highlights={[["2"], ["6"], ["10"], ["12"], ["14"], ["18"], ["22"], ["28"], ["36"]]} -import HelloModuleService from "./service" -// add necessary imports -import { ModulesSdkUtils } from "@medusajs/utils" -import { MyCustom } from "./models/my-custom" - -// define useful constants -const moduleName = "hello" -const pathToMigrations = __dirname + "/migrations" - -// assemble object to pass to utility functions -const migrationScriptOptions = { - // the module's name - moduleName, - // the data models of the modules - models: { - MyCustom, - }, - // the path to the migrations directory - pathToMigrations, -} - -// create and export the script that runs migrations -export const runMigrations = ModulesSdkUtils - .buildMigrationScript( - migrationScriptOptions - ) - -// create and export the script that reverts migrations -export const revertMigration = ModulesSdkUtils - .buildRevertMigrationScript( - migrationScriptOptions - ) - -export default { - service: HelloModuleService, - // add the run and revert migration scripts to the module's definition - runMigrations, - revertMigration, -} -``` - -After importing `ModulesSdkUtils`, you use its `buildMigrationScript` function to create the script that runs the migration, and its `buildRevertMigrationScript` function to create the script that reverts the migration. - -Both the `buildMigrationScript` and `buildRevertMigrationScript` accept the same object type as a parameter, which has the following properties: - -- `moduleName`: The name of the module that the migrations belong to. -- `models`: An object of the module's data models. -- `pathToMigrations`: The path to the `migrations` directory. - -Both created scripts must be exported in the file and within the module's definition object. - ### Run Migration To reflect the changes in the migration, transpile your source files using the `build` command, then run the `migration` command: diff --git a/www/apps/book/app/storefront-development/tips/page.mdx b/www/apps/book/app/storefront-development/tips/page.mdx index 29d11dae45..265665b51e 100644 --- a/www/apps/book/app/storefront-development/tips/page.mdx +++ b/www/apps/book/app/storefront-development/tips/page.mdx @@ -24,15 +24,17 @@ To send requests from the storefront to the Medusa application’s Store API Rou ## Configure CORS -The Medusa application’s API routes are guarded by a CORS middleware. Make sure to set the `store_cors` configuration of your Medusa application to the storefront’s URL. +The Medusa application’s API routes are guarded by a CORS middleware. Make sure to set the `storeCors` property of the `http` configuration in `medusa-config.js` to the storefront’s URL. For example: ```js title="medusa-config.js" module.exports = { projectConfig: { - store_cors: "http://localhost:3000", - // ... + http: { + storeCors: "http://localhost:3000", + // ... + } }, // ... } diff --git a/www/apps/book/sidebar.mjs b/www/apps/book/sidebar.mjs index 191053ae4e..63cf33e318 100644 --- a/www/apps/book/sidebar.mjs +++ b/www/apps/book/sidebar.mjs @@ -102,10 +102,6 @@ export const sidebar = sidebarAttachHrefCommonOptions( path: "/advanced-development/modules/container", title: "Module's Container", }, - { - path: "/advanced-development/modules/connection-loader", - title: "Database Connection Loader", - }, { path: "/advanced-development/modules/service-factory", title: "Service Factory", @@ -130,6 +126,10 @@ export const sidebar = sidebarAttachHrefCommonOptions( path: "/advanced-development/modules/link-modules", title: "Link Modules", }, + { + path: "/advanced-development/modules/remote-link", + title: "Remote Link", + }, ], }, { @@ -200,6 +200,10 @@ export const sidebar = sidebarAttachHrefCommonOptions( }, ], }, + { + path: "/advanced-development/custom-cli-scripts", + title: "Custom CLI Scripts", + }, { path: "/advanced-development/admin", title: "Admin Development", @@ -243,26 +247,8 @@ export const sidebar = sidebarAttachHrefCommonOptions( ], }, { - path: "/architectural-concepts", - title: "Architectural Concepts", - children: [ - { - path: "/architectural-concepts/architectural-modules", - title: "Architectural Modules", - }, - { - path: "/architectural-concepts/cache-module", - title: "Cache Module", - }, - { - path: "/architectural-concepts/event-module", - title: "Event Module", - }, - { - path: "/architectural-concepts/file-module", - title: "File Module", - }, - ], + path: "/architectural-concepts/architectural-modules", + title: "Architectural Modules", }, { path: "/debugging-and-testing", diff --git a/www/apps/resources/app/architectural-modules/cache/page.mdx b/www/apps/resources/app/architectural-modules/cache/page.mdx index e7f1084492..160fd265e5 100644 --- a/www/apps/resources/app/architectural-modules/cache/page.mdx +++ b/www/apps/resources/app/architectural-modules/cache/page.mdx @@ -6,6 +6,22 @@ export const metadata = { # {metadata.title} -Learn how to create a cache module in [this guide](./create/page.mdx). +A Cache Module is used to cache the results of computations such as price selection or various tax calculations. + +The underlying database, third-party service, or caching logic is flexible since it's implemented in a module. You can choose from Medusa’s cache modules or create your own to support something more suitable for your architecture. + +--- + +## List of Cache Modules + +By default, Medusa uses the In-Memory Cache Module. This module uses a plain JavaScript Map object to store the cache data. + +This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the Redis Cache Module. + +--- + +## Create a Cache Module + +To create a cache module, refer to [this guide](./create/page.mdx). diff --git a/www/apps/resources/app/architectural-modules/event/page.mdx b/www/apps/resources/app/architectural-modules/event/page.mdx index 6572ee134e..d9dce41e9c 100644 --- a/www/apps/resources/app/architectural-modules/event/page.mdx +++ b/www/apps/resources/app/architectural-modules/event/page.mdx @@ -6,6 +6,22 @@ export const metadata = { # {metadata.title} -Learn how to create a event module in [this guide](./create/page.mdx). +An Event Module implements the underlying publish/subscribe system that handles queueing events, emitting them, and executing their subscribers. + +This makes the event architecture customizable, as you can either choose one of Medusa’s event modules or create your own. + +--- + +## List of Event Modules + +By default, Medusa uses the Local Event Module. This module uses Node’s EventEmitter to implement the publish/subscribe system. + +This is useful for development. However, for production, it’s highly recommended to use other Event Modules, Redis Event Module. + +--- + +## Create a Event Module + +To create an event module, refer to [this guide](./create/page.mdx). diff --git a/www/apps/resources/app/architectural-modules/file/page.mdx b/www/apps/resources/app/architectural-modules/file/page.mdx index d5db18089b..6b6a7f0f9f 100644 --- a/www/apps/resources/app/architectural-modules/file/page.mdx +++ b/www/apps/resources/app/architectural-modules/file/page.mdx @@ -6,6 +6,22 @@ export const metadata = { # {metadata.title} -Learn how to create a file provider module in [this guide](/references/file-provider-module). +A File Module exposes the functionalities to upload assets, such as product images, to the Medusa application. + +--- + +## What is a File Provider Module? + +A file provider module implements the logic of handling uploads and downloads. The File Module must have one file provider module configured. + +By default, Medusa uses the Local File Module. This module uploads files to the `uploads` directory of your Medusa application. + +This is useful for development. However, for production, it’s highly recommended to use other File Modules, such as the S3 Module. + +--- + +## Create a File Provider Module + +To create a file provider module, refer to [this guide](/references/file-provider-module). diff --git a/www/apps/resources/app/architectural-modules/file/s3/page.mdx b/www/apps/resources/app/architectural-modules/file/s3/page.mdx new file mode 100644 index 0000000000..611db727d1 --- /dev/null +++ b/www/apps/resources/app/architectural-modules/file/s3/page.mdx @@ -0,0 +1,311 @@ +import { Table, Tabs, TabsList, TabsContent, TabsContentWrapper, TabsTrigger } from "docs-ui" + +export const metadata = { + title: `S3 File Provider Module`, +} + +# {metadata.title} + +The S3 File Provider Module integrates Amazon S3 and services following a compatible API (such as MinIO or DigitalOcean Spaces) to store files uploaded to your Medusa application. + +--- + +## Prerequisites + + + + AWS S3 + MinIO + DigitalOcean Spaces + + + + + - [AWS account](https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin). + - [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html) with the "Public Access setting" enabled. + - [AWS user with AmazonS3FullAccess permissions](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-and-attach-iam-policy.html). + - [AWS user access key ID and secret access key](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey). + - Change your [bucket's policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html) to the following: + + ```json + { + "Version": "2012-10-17", + "Id": "Policy1397632521960", + "Statement": [ + { + "Sid": "Stmt1397633323327", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::{bucket_name}/*" + } + ] + } + ``` + + Make sure to replace `{bucket_name}` with the name of the bucket you created. + + + + + - [Install MinIO](https://min.io/docs/minio/linux/index.html). + - Change port to `9001` using the [console address](https://min.io/docs/minio/linux/reference/minio-server/minio-server.html#minio.server.-console-address) and [address](https://min.io/docs/minio/linux/reference/minio-server/minio-server.html#minio.server.-address) CLI options. + - [MinIO bucket with public access policy](https://min.io/docs/minio/linux/administration/console/managing-objects.html#creating-buckets). + - [MinIO access and secret access key](https://min.io/docs/minio/linux/administration/console/security-and-access.html#id1). + + + + + - [DigitalOcean account](https://cloud.digitalocean.com/registrations/new). + - [DigitalOcean Spaces bucket](https://docs.digitalocean.com/products/spaces/how-to/create/). + - [DigitalOcean Spaces access and secret access keys](https://docs.digitalocean.com/products/spaces/how-to/manage-access/#access-keys). + + + + + +--- + +## Install the S3 File Module + +To install the S3 File Provider Module, run the following command in the directory of your Medusa application: + +```bash npm2yarn +npm install @medusajs/file-s3 +``` + +Next, add the module into the `providers` array of the File Module: + + + +The File Module accepts one provider only. + + + +```js title="medusa-config.js" +module.exports = { + // ... + modules: { + // ... + [Modules.FILE]: { + resolve: "@medusajs/file", + options: { + providers: [ + { + resolve: "@medusajs/file-s3", + options: { + config: { + s3: { + file_url: process.env.S3_FILE_URL, + access_key_id: process.env.S3_ACCESS_KEY_ID, + secret_access_key: process.env.S3_SECRET_ACCESS_KEY, + region: process.env.S3_REGION, + bucket: process.env.S3_BUCKET, + endpoint: process.env.S3_ENDPOINT, + // other options... + }, + }, + }, + }, + ], + }, + }, + }, +} +``` + +### S3 File Module Options + + + + + Option + Description + Default + + + + + + + `file_url` + + + + + The base URL to upload files to. + + - For AWS S3, the endpoint is of the format `https://{bucket}.s3.{region}.amazonaws.com` + - For MinIO, it's the URL to the MinIO server. + - For DigitalOcean Spaces, it's either the Origin Endpoint or the CDN endpoint of your Spaces Object Storage bucket. + + + + + \- + + + + + + + `access_key_id` + + + + + The AWS or (S3 compatible) user's access key ID. + + + + + \- + + + + + + + `secret_access_key` + + + + + The AWS or (S3 compatible) user's secret access key. + + + + + \- + + + + + + + `region` + + + + + The bucket's region code. + + + + + \- + + + + + + + `bucket` + + + + + The bucket's name. + + + + + \- + + + + + + + `endpoint` + + + + + The URL to the AWS S3 (or compatible S3 API) server. + + - For AWS S3, the endpoint is of the format `{bucket}.s3.{region}.amazonaws.com` + - For MinIO, it's the URL to the MinIO server. + - For DigitalOcean Spaces, it's the Spaces Origin Endpoint. + + + + + \- + + + + + + + `prefix` + + + + + A string to prefix each uploaded file's name. + + + + + \- + + + + + + + `cache_control` + + + + + A string indicating how long objects remain in the AWS S3 (or compatible S3 API) cache. + + + + + `public, max-age=31536000` + + + + + + + `download_file_duration` + + + + + A number indicating the expiry time of presigned URLs in seconds. + + + + + `3600` (An hour) + + + + + + + `additional_client_config` + + + + + Any additional configurations to pass to the S3 client. + + Refer to [this AWS API reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html) for a full list of accepted configuration. + + + + + \- + + + + +
diff --git a/www/apps/resources/app/architectural-modules/notification/local/page.mdx b/www/apps/resources/app/architectural-modules/notification/local/page.mdx new file mode 100644 index 0000000000..f3260f3876 --- /dev/null +++ b/www/apps/resources/app/architectural-modules/notification/local/page.mdx @@ -0,0 +1,80 @@ +import { Table } from "docs-ui" + +export const metadata = { + title: `Local Notification Provider Module`, +} + +# {metadata.title} + +The Local Notification Provider Module simulates sending a notification, but only logs the notification's details in the terminal. This is useful for development. + +--- + +## Install the Local Notification Module + +To install the Local Notification Provider Module, run the following command in the directory of your Medusa application: + +```bash npm2yarn +npm install @medusajs/notification-local +``` + +Next, add the module into the `providers` array of the Notification Module: + + + +Only one provider can be defined for a channel. + + + +```js title="medusa-config.js" +module.exports = { + // ... + modules: { + // ... + [Modules.NOTIFICATION]: { + resolve: "@medusajs/notification", + options: { + providers: [ + // ... + { + resolve: "@medusajs/notification-local", + options: { + config: { + local: { + channels: ["email"] + }, + }, + }, + }, + ], + }, + }, + }, +} +``` + +### Local Notification Module Options + + + + + Option + Description + + + + + + + `channels` + + + + + The channels this notification module is used to send notifications for. While the local notification module doesn't actually send the notification, + it's important to specify its channels to make sure it's used when a notification for that channel is created. + + + + +
diff --git a/www/apps/resources/app/architectural-modules/notification/page.mdx b/www/apps/resources/app/architectural-modules/notification/page.mdx new file mode 100644 index 0000000000..82e3ca5058 --- /dev/null +++ b/www/apps/resources/app/architectural-modules/notification/page.mdx @@ -0,0 +1,66 @@ +import { ChildDocs } from "docs-ui" + +export const metadata = { + title: `Notification Provider Modules`, +} + +# {metadata.title} + +A Notification Module exposes the functionalities to send a notification to a customer or user. For example, sending an order confirmation email. + +You can resolve the Notification Module and send notifications in API routes, subscribers, or other resources. + +--- + +## What is a Notification Provider Module? + +A notification provider module implements the logic of sending the notification. It either integrates a third-party service or uses custom logic to send the notification. + +By default, Medusa uses the Local Notification Module which only simulates sending the notification by logging a message in the terminal. + +Medusa provides other Notification Modules that actually send notifications, such as the SendGrid Notification Provider Module. + + + +--- + +## Notification Provider Module Channels + +When you send a notification, you specify the channel to send it through, such as `email` or `sms`. Each provider defined in the Notification Module's `providers` option has a `channels` option specifying which channels it can be used in. Only one provider can be setup for each channel. + +For example: + +```js title="medusa-config.js" highlights={[["15"]]} +module.exports = { + // ... + modules: { + // ... + [Modules.NOTIFICATION]: { + resolve: "@medusajs/notification", + options: { + providers: [ + // ... + { + resolve: "@medusajs/notification-local", + options: { + config: { + local: { + channels: ["email"] + }, + }, + }, + }, + ], + }, + }, + }, +} +``` + +The `channels` option is an array of strings indicating the channels this provider is used for. + +--- + +## Create a Notification Provider Module + +To create a notification provider module, refer to [this guide](/references/notification-provider-module). diff --git a/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx b/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx new file mode 100644 index 0000000000..876b5ff7d2 --- /dev/null +++ b/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx @@ -0,0 +1,86 @@ +import { TypeList } from "docs-ui" + +export const metadata = { + title: `Send Notification with the Notification Module`, +} + +# {metadata.title} + +In this guide, you'll learn how to send a notification using the Notification Module. + +## Use the Create Method + +In your resource, such as a subscriber, resolve the Notification Module's main service and use its `create` method: + +export const highlights = [ + ["12", "notificationModuleService", "Resolve the Notification Module."], + ["17", "create", "Create the notification to be sent."], + ["19", '"email"', "Use the provider module defined for the `email` channel to send an email."], + ["20", '"product-created"', "The ID of the template defined in the third-party service, such as SendGrid."], + ["21", "data", "The data to pass to the template defined in the third-party service."] +] + +```ts title="src/subscribers/product-created.ts" highlights={highlights} +import type { + SubscriberArgs, + SubscriberConfig, +} from "@medusajs/medusa" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { INotificationModuleService } from "@medusajs/types" + +export default async function productCreateHandler({ + data, + container +}: SubscriberArgs<{ id: string }>) { + const notificationModuleService: INotificationModuleService = + container.resolve( + ModuleRegistrationName.NOTIFICATION + ) + + await notificationModuleService.create({ + to: "shahednasser@gmail.com", + channel: "email", + template: "product-created", + data: "data" in data ? data.data : data + }) +} + +export const config: SubscriberConfig = { + event: "product.created", +} +``` + +The `create` method accepts an object or an array of objects having the following properties: + +`", + description: "The data to pass along to the template, if necessary." + } + ]} + sectionTitle="Use the Create Method" +/> + +{/* TODO add once reference for type once generated */} + +{/* For a full list of properties accepted, refer to [this guide](/references/notification-provider-module#create). */} diff --git a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx new file mode 100644 index 0000000000..9f0f06feb9 --- /dev/null +++ b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx @@ -0,0 +1,192 @@ +import { Table } from "docs-ui" + +export const metadata = { + title: `SendGrid Notification Provider Module`, +} + +# {metadata.title} + +The SendGrid Notification Provider Module integrates [SendGrid](https://sendgrid.com) to send emails to users and customers. + +--- + +## Install the SendGrid Notification Module + + + +- [SendGrid account](https://signup.sendgrid.com) +- [Setup SendGrid single sender](https://docs.sendgrid.com/ui/sending-email/sender-verification) +- [SendGrid API Key](https://docs.sendgrid.com/ui/account-and-settings/api-keys) + + + +To install the SendGrid Notification Provider Module, run the following command in the directory of your Medusa application: + +```bash npm2yarn +npm install @medusajs/notification-sendgrid +``` + +Next, add the module into the `providers` array of the Notification Module: + + + +Only one provider can be defined for a channel. + + + +```js title="medusa-config.js" +module.exports = { + // ... + modules: { + // ... + [Modules.NOTIFICATION]: { + resolve: "@medusajs/notification", + options: { + providers: [ + // ... + { + resolve: "@medusajs/notification-sendgrid", + options: { + config: { + sendgrid: { + channels: ["email"], + api_key: process.env.SENDGRID_API_KEY, + from: process.env.SENDGRID_FROM + }, + }, + }, + }, + ], + }, + }, + }, +} +``` + +### Environment Variables + +Make sure to add the following environment variables: + +```bash +SENDGRID_API_KEY= +SENDGRID_FROM= +``` + +### SendGrid Notification Module Options + + + + + Option + Description + + + + + + + `channels` + + + + + The channels this notification module is used to send notifications for. Only one provider can be defined for a channel. + + + + + + + `api_key` + + + + + The SendGrid API key. + + + + + + + `from` + + + + + The SendGrid from email. + + + + +
+ +--- + +## SendGrid Templates + +When you send a notification, you must specify the ID of the template to use in SendGrid. + +Refer to [this SendGrid documentation guide](https://docs.sendgrid.com/ui/sending-email/how-to-send-an-email-with-dynamic-templates) on how to create templates for your different email types. + +--- + +## Test out the Module + +To test the module out, create a simple subscriber at `src/subscribers/product-created.ts` with the following content: + +export const highlights = [ + ["12", "notificationModuleService", "Resolve the Notification Module."], + ["17", "create", "Create the notification to be sent."], + ["19", '"email"', "By specifying the `email` channel, SendGrid will be used to send the notification."], + ["20", '"product-created"', "The ID of the template defined in SendGrid."], + ["21", "data", "The data to pass to the template defined in SendGrid."] +] + +```ts title="src/subscribers/product-created.ts" highlights={highlights} +import type { + SubscriberArgs, + SubscriberConfig, +} from "@medusajs/medusa" +import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { INotificationModuleService } from "@medusajs/types" + +export default async function productCreateHandler({ + data, + container +}: SubscriberArgs<{ id: string }>) { + const notificationModuleService: INotificationModuleService = + container.resolve( + ModuleRegistrationName.NOTIFICATION + ) + + await notificationModuleService.create({ + to: "test@gmail.com", + channel: "email", + template: "product-created", + data: "data" in data ? data.data : data + }) +} + +export const config: SubscriberConfig = { + event: "product.created", +} +``` + +In this subscriber: + +- Resolve the Notification Module's main service. +- Use the `create` method of the main service to create a notification to be sent to the specified email. +- By specifying the `email` channel, the SendGrid Notification Provider Module is used to send the notification. +- The `template` property of the `create` method's parameter specifies the ID of the template defined in SendGrid. +- The `data` property allows you to pass data to the template in SendGrid. + +Then, start the Medusa application: + +```bash npm2yarn +npm run dev +``` + +{/* TODO add links */} + +And create a product either using the [API route](!api!/api/admin#products_postproducts) or the Medusa Admin. This runs the subscriber and sends an email using SendGrid. diff --git a/www/apps/resources/app/architectural-modules/workflow-engine/page.mdx b/www/apps/resources/app/architectural-modules/workflow-engine/page.mdx new file mode 100644 index 0000000000..f62462a58d --- /dev/null +++ b/www/apps/resources/app/architectural-modules/workflow-engine/page.mdx @@ -0,0 +1,13 @@ +import { ChildDocs } from "docs-ui" + +export const metadata = { + title: `Workflow Engine Modules`, +} + +# {metadata.title} + +Workflow engine modules handle tracking and recording the transactions and statuses of workflows and their steps. + +Medusa uses the In-Memory Workflow Engine Module by default. For production purposes, it's recommended to use the Redis Engine Module instead. + + diff --git a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx index dee0af09c1..56c29180fa 100644 --- a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx @@ -55,9 +55,9 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j return } - const { jwt_secret } = - req.scope.resolve("configModule").projectConfig - const token = jwt.sign(authUser, jwt_secret) + const { jwtSecret } = + req.scope.resolve("configModule").projectConfig.http + const token = jwt.sign(authUser, jwtSecret) res.status(200).json({ token }) } @@ -153,9 +153,9 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j throw new MedusaError(MedusaError.Types.UNAUTHORIZED, error) } - const { jwt_secret } = - req.scope.resolve("configModule").projectConfig - const token = jwt.sign(authUser, jwt_secret) + const { jwtSecret } = + req.scope.resolve("configModule").projectConfig.http + const token = jwt.sign(authUser, jwtSecret) if (successRedirectUrl) { const url = new URL(successRedirectUrl!) diff --git a/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx b/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx index 63d5868031..8f5733abe8 100644 --- a/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/module-options/page.mdx @@ -227,6 +227,6 @@ GOOGLE_SUCCESS_REDIRECT_URL= ## Auth CORS -The Medusa application's authentication API routes are defined under the `/auth` prefix that requires setting the `auth_cors` configuration. So, before using these routes, make sure to set that configuration. +The Medusa application's authentication API routes are defined under the `/auth` prefix that requires setting the `authCors` property of the `http` configuration. So, before using these routes, make sure to set that configuration. -Refer to [Medusa's configuration guide](/references/medusa-config#auth_cors) for more details. +Refer to [Medusa's configuration guide](/references/medusa-config#authCors) for more details. diff --git a/www/apps/resources/app/commerce-modules/auth/persisting-auth-user/page.mdx b/www/apps/resources/app/commerce-modules/auth/persisting-auth-user/page.mdx index ece75e1578..9b5f8381aa 100644 --- a/www/apps/resources/app/commerce-modules/auth/persisting-auth-user/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/persisting-auth-user/page.mdx @@ -45,10 +45,10 @@ const { // ... const { - jwt_secret, -} = req.scope.resolve("configModule").projectConfig + jwtSecret, +} = req.scope.resolve("configModule").projectConfig.http -const token = jwt.sign(authUser, jwt_secret) +const token = jwt.sign(authUser, jwtSecret) ``` Then, the token is passed in the header of subsequent requests in the Authorization Bearer header. diff --git a/www/apps/resources/app/deployment/medusa-application/general/page.mdx b/www/apps/resources/app/deployment/medusa-application/general/page.mdx index d7419e9ede..13f9bf2c7e 100644 --- a/www/apps/resources/app/deployment/medusa-application/general/page.mdx +++ b/www/apps/resources/app/deployment/medusa-application/general/page.mdx @@ -32,7 +32,7 @@ Make sure the `start` script in your `package.json` runs migrations, the `build` ## Set SSL Database Option -In production, it’s recommended to set the [database_extra option](/medusa-configurations) in `medusa-config.js` to disable the `ssl.rejectUnauthorized` option: +In production, it’s recommended to set the [database_extra option](/references/medusa-config#database_extra) in `medusa-config.js` to disable the `ssl.rejectUnauthorized` option: ```js title="medusa-config.js" highlights={[["4"]]} module.exports = { @@ -151,7 +151,7 @@ After you’ve deployed your Medusa application, you can test it out in differen ## Set Up CORS Configuration -To connect your storefront and, if deployed separately, your admin dashboard to your deployed Medusa application, set up the [admin_cors](/medusa-configurations#admin_cors) and [store_cors](/medusa-configurations#store_cors) configurations in `medusa-config.js`. +To connect your storefront and, if deployed separately, your admin dashboard to your deployed Medusa application, set up the [adminCors](/references/medusa-config#adminCors) and [storeCors](/references/medusa-config#storeCors) properties of the `http` configuration in `medusa-config.js`. --- diff --git a/www/apps/resources/app/medusa-cli/page.mdx b/www/apps/resources/app/medusa-cli/page.mdx index bf6ad92c53..c2c792d990 100644 --- a/www/apps/resources/app/medusa-cli/page.mdx +++ b/www/apps/resources/app/medusa-cli/page.mdx @@ -561,6 +561,62 @@ npx medusa user --email [--password ] +### exec + +Run a custom CLI script. Learn more about it in [this guide](!docs!/advanced-development/custom-cli-scripts). + +```bash +npx medusa exec [file] [args...] +``` + +#### Arguments + + + + + Argument + Description + Required + + + + + + + `file` + + + + + The path to a JavaScript file holding the function to execute. + + + + + Yes + + + + + + + `args` + + + + + A list of arguments to pass to the function. These arguments are passed in the `args` property of the function's object parameter. + + + + + No + + + + +
+ ### start-cluster Starts the Medusa application in [cluster mode](https://expressjs.com/en/advanced/best-practice-performance.html#run-your-app-in-a-cluster). Running in cluster mode significantly improves performance as the workload and tasks are distributed among all available instances instead of a single one. diff --git a/www/apps/resources/app/troubleshooting/_sections/create-medusa-app-errors/forwarding.mdx b/www/apps/resources/app/troubleshooting/_sections/create-medusa-app-errors/forwarding.mdx index d153026444..b522850099 100644 --- a/www/apps/resources/app/troubleshooting/_sections/create-medusa-app-errors/forwarding.mdx +++ b/www/apps/resources/app/troubleshooting/_sections/create-medusa-app-errors/forwarding.mdx @@ -4,7 +4,7 @@ If you're running the Medusa backend through tools like VSCode or GitHub Codespa - [VSCode local development.](https://code.visualstudio.com/docs/editor/port-forwarding) - [VSCode remote development.](https://code.visualstudio.com/docs/remote/ssh#_forwarding-a-port-creating-ssh-tunnel) - [GitHub Codespaces.](https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace) -2. If your tool or IDE exposes an address other than `localhost`, such as `127.0.0.1`, make sure to add that address to the [admin_cors](/references/medusa-config) Medusa configuration. Your tool will show you what the forwarded address is. +2. If your tool or IDE exposes an address other than `localhost`, such as `127.0.0.1`, make sure to add that address to the [adminCors](/references/medusa-config#adminCors) Medusa configuration. Your tool will show you what the forwarded address is. After setting these configurations, run your Medusa backend and try again. If you couldn't create an admin user before, run the following command in the root directory of your Medusa project to create an admin user: diff --git a/www/apps/resources/app/troubleshooting/_sections/database-errors/docker.mdx b/www/apps/resources/app/troubleshooting/_sections/database-errors/docker.mdx index 22d7b10c3f..91bf825465 100644 --- a/www/apps/resources/app/troubleshooting/_sections/database-errors/docker.mdx +++ b/www/apps/resources/app/troubleshooting/_sections/database-errors/docker.mdx @@ -22,4 +22,4 @@ npx create-medusa-app@latest --db-url "postgres://user:password@localhost:` is the exposed port if it's different than `5432`. -Refer to the [database_url configuration documentation](/medusa-configurations#database_url) to learn how to set the database URL for an installed Medusa backend. +Refer to the [database_url configuration documentation](/references/medusa-config#database_url) to learn how to set the database URL for an installed Medusa backend. diff --git a/www/apps/resources/generated/files-map.mjs b/www/apps/resources/generated/files-map.mjs index aa3476be1e..5c5578e0af 100644 --- a/www/apps/resources/generated/files-map.mjs +++ b/www/apps/resources/generated/files-map.mjs @@ -191,6 +191,26 @@ export const filesMap = [ "filePath": "/www/apps/resources/app/architectural-modules/file/page.mdx", "pathname": "/architectural-modules/file" }, + { + "filePath": "/www/apps/resources/app/architectural-modules/file/s3/page.mdx", + "pathname": "/architectural-modules/file/s3" + }, + { + "filePath": "/www/apps/resources/app/architectural-modules/notification/local/page.mdx", + "pathname": "/architectural-modules/notification/local" + }, + { + "filePath": "/www/apps/resources/app/architectural-modules/notification/page.mdx", + "pathname": "/architectural-modules/notification" + }, + { + "filePath": "/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx", + "pathname": "/architectural-modules/notification/send-notification" + }, + { + "filePath": "/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx", + "pathname": "/architectural-modules/notification/sendgrid" + }, { "filePath": "/www/apps/resources/app/architectural-modules/page.mdx", "pathname": "/architectural-modules" @@ -199,6 +219,10 @@ export const filesMap = [ "filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/in-memory/page.mdx", "pathname": "/architectural-modules/workflow-engine/in-memory" }, + { + "filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/page.mdx", + "pathname": "/architectural-modules/workflow-engine" + }, { "filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx", "pathname": "/architectural-modules/workflow-engine/redis" @@ -6400,16 +6424,8 @@ export const filesMap = [ "pathname": "/references/modules/workflows" }, { - "filePath": "/www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx", - "pathname": "/references/notification/classes/notification.AbstractNotificationService" - }, - { - "filePath": "/www/apps/resources/references/notification/interfaces/notification.INotificationService/page.mdx", - "pathname": "/references/notification/interfaces/notification.INotificationService" - }, - { - "filePath": "/www/apps/resources/references/notification/interfaces/notification.ReturnedData/page.mdx", - "pathname": "/references/notification/interfaces/notification.ReturnedData" + "filePath": "/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx", + "pathname": "/references/notification/classes/notification.AbstractNotificationProviderService" }, { "filePath": "/www/apps/resources/references/order/IMessageAggregator/methods/order.IMessageAggregator.clearMessages/page.mdx", diff --git a/www/apps/resources/generated/sidebar.mjs b/www/apps/resources/generated/sidebar.mjs index dd3fdcfbae..560819d266 100644 --- a/www/apps/resources/generated/sidebar.mjs +++ b/www/apps/resources/generated/sidebar.mjs @@ -6757,6 +6757,13 @@ export const generatedSidebar = [ "title": "Local", "children": [] }, + { + "loaded": true, + "isPathHref": true, + "path": "/architectural-modules/file/s3", + "title": "AWS S3 (and Compatible APIs)", + "children": [] + }, { "loaded": true, "isPathHref": true, @@ -6776,6 +6783,51 @@ export const generatedSidebar = [ { "loaded": true, "isPathHref": true, + "path": "/architectural-modules/notification", + "title": "Notification Provider Modules", + "hasTitleStyling": true, + "children": [ + { + "loaded": true, + "isPathHref": true, + "path": "/architectural-modules/notification/local", + "title": "Local", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "path": "/architectural-modules/notification/sendgrid", + "title": "SendGrid", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "title": "Guides", + "children": [ + { + "loaded": true, + "isPathHref": true, + "path": "/architectural-modules/notification/send-notification", + "title": "Send Notification", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "path": "/references/notification-provider-module", + "title": "Create Notification Module", + "children": [] + } + ] + } + ] + }, + { + "loaded": true, + "isPathHref": true, + "path": "/architectural-modules/workflow-engine", "title": "Workflow Engine Modules", "hasTitleStyling": true, "children": [ diff --git a/www/apps/resources/generated/slug-changes.mjs b/www/apps/resources/generated/slug-changes.mjs index 026304b8ed..246ff0432a 100644 --- a/www/apps/resources/generated/slug-changes.mjs +++ b/www/apps/resources/generated/slug-changes.mjs @@ -1880,9 +1880,9 @@ export const slugChanges = [ "filePath": "/www/apps/resources/references/modules/workflows/page.mdx" }, { - "origSlug": "/references/notification/classes/notification.AbstractNotificationService", - "newSlug": "/references/notification-service", - "filePath": "/www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx" + "origSlug": "/references/notification/classes/notification.AbstractNotificationProviderService", + "newSlug": "/references/notification-provider-module", + "filePath": "/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx" }, { "origSlug": "/references/order/IOrderModuleService/methods/order.IOrderModuleService.addOrderAction", diff --git a/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx b/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx index c172863840..d53d60ffb1 100644 --- a/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx +++ b/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx @@ -99,26 +99,27 @@ The File Module accepts one provider only. ```js title="medusa-config.js" -module.exports = { +const { Modules } = require("@medusajs/modules-sdk") + +// ... + +const modules = { // ... - modules: { - // ... - [Modules.FILE]: { - resolve: "@medusajs/file", - options: { - providers: [ - { - resolve: "./dist/modules/my-file", - options: { - config: { - "my-file": { - // provider options... - }, + [Modules.FILE]: { + resolve: "@medusajs/file", + options: { + providers: [ + { + resolve: "./dist/modules/my-file", + options: { + config: { + "my-file": { + // provider options... }, }, }, - ], - }, + }, + ], }, }, } diff --git a/www/apps/resources/references/modules/notification/page.mdx b/www/apps/resources/references/modules/notification/page.mdx index b7182208ec..d1557398d0 100644 --- a/www/apps/resources/references/modules/notification/page.mdx +++ b/www/apps/resources/references/modules/notification/page.mdx @@ -4,9 +4,4 @@ import { TypeList } from "docs-ui" ## Classes -- [AbstractNotificationService](../../notification/classes/notification.AbstractNotificationService/page.mdx) - -## Interfaces - -- [ReturnedData](../../notification/interfaces/notification.ReturnedData/page.mdx) -- [INotificationService](../../notification/interfaces/notification.INotificationService/page.mdx) +- [AbstractNotificationProviderService](../../notification/classes/notification.AbstractNotificationProviderService/page.mdx) diff --git a/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx b/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx new file mode 100644 index 0000000000..d7bdbd63a1 --- /dev/null +++ b/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx @@ -0,0 +1,103 @@ +--- +slug: /references/notification-provider-module +--- + +import { TypeList } from "docs-ui" + +# How to Create a Notification Provider Module + +In this document, you’ll learn how to create a notification provider module and the methods you must implement in it. + +--- + +## 1. Create Module Directory + +Start by creating a new directory for your module. For example, `src/modules/my-notification`. + +--- + +## 2. Create the Notification Provider Service + +Create the file `src/modules/my-notification/service.ts` that holds the implementation of the notification service. + +The Notification Provider Module's main service must extend the `AbstractNotificationProviderService` class imported from `@medusajs/utils`: + +```ts title="src/modules/my-notification/service.ts" +import { + AbstractNotificationProviderService +} from "@medusajs/utils" + +class MyNotificationProviderService extends AbstractNotificationProviderService { + // TODO add methods +} + +export default MyNotificationProviderService +``` + +### constructor + +### send + +#### Parameters + + + +#### Returns + + + +--- + +## 3. Create Module Definition File + +Create the file `src/modules/my-notification/index.ts` with the following content: + +```ts title="src/modules/my-notification/index.ts" +import MyNotificationProviderService from "./service" + +export default { + service: MyNotificationProviderService, +} +``` + +This exports the module's definition, indicating that the `MyNotificationProviderService` is the main service of the module. + +--- + +## 4. Use Module + +To use your Notification Provider Module, add it to the `providers` array of the Notification Module: + + + +The Notification Module accepts one provider per channel. + + + +```js title="medusa-config.js" +const { Modules } = require("@medusajs/modules-sdk") + +// ... + +const modules = { + // ... + [Modules.NOTIFICATION]: { + resolve: "@medusajs/notification", + options: { + providers: [ + { + resolve: "./dist/modules/my-notification", + options: { + config: { + "my-notification": { + channels: ["email"], + // provider options... + }, + }, + }, + }, + ], + }, + }, +} +``` diff --git a/www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx b/www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx deleted file mode 100644 index b53dc46b24..0000000000 --- a/www/apps/resources/references/notification/classes/notification.AbstractNotificationService/page.mdx +++ /dev/null @@ -1,287 +0,0 @@ ---- -slug: /references/notification-service ---- - -import { TypeList } from "docs-ui" - -# How to Create a Notification Provider - -In this document, you’ll learn how to create a notification provider in the Medusa backend and the methods you must implement in it. Learn more about the notification architecture in [this documentation](https://docs.medusajs.com/development/notification/overview) - -## Overview - -:::note[Prerequisites] - -Before creating a Notification Provider, [install an event bus module](https://docs.medusajs.com/development/events/modules/redis). - -::: - -A Notification Provider is a provider that handles sending and resending of notifications. - -To create a Notification Provider, create a TypeScript or JavaScript file in `src/services`. The name of the file is the name of the provider -(for example, `sendgrid.ts`). The file must export a class that extends the `AbstractNotificationService` class imported from `@medusajs/medusa`. - -For example, create the file `src/services/email-sender.ts` with the following content: - -```ts title="src/services/email-sender.ts" -import { AbstractNotificationService } from "@medusajs/medusa" -import { EntityManager } from "typeorm" - -class EmailSenderService extends AbstractNotificationService { - protected manager_: EntityManager - protected transactionManager_: EntityManager - - sendNotification( - event: string, - data: unknown, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - throw new Error("Method not implemented.") - } - resendNotification( - notification: unknown, - config: unknown, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - throw new Error("Method not implemented.") - } - -} - -export default EmailSenderService -``` - ---- - -## Identifier Property - -The `NotificationProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the notification provider -class is used when the Notification Provider is created in the database. - -The value of this property is also used later when you want to subscribe the Notification Provider to events in a [Loader](https://docs.medusajs.com/development/loaders/overview). - -For example: - -```ts -class EmailSenderService extends AbstractNotificationService { - static identifier = "email-sender" - // ... -} -``` - ---- - -## constructor - -You can use the `constructor` of your notification provider to access the different services in Medusa through dependency injection. - -You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, -you can initialize it in the constructor and use it in other methods in the service. - -Additionally, if you’re creating your notification provider as an external plugin to be installed on any Medusa backend and you want to access the options -added for the plugin, you can access it in the constructor. - -### Example - -```ts -// ... -import { AbstractNotificationService, OrderService } from "@medusajs/medusa" -import { EntityManager } from "typeorm" - -class EmailSenderService extends AbstractNotificationService { - // ... - protected orderService: OrderService - - constructor(container, options) { - super(container) - // you can access options here in case you're - // using a plugin - - this.orderService = container.orderService - - // you can also initialize a client that - // communicates with a third-party service. - this.client = new Client(options) - } - - // ... -} - -export default EmailSenderService -``` - -### Parameters - -`","description":"An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"config","type":"`Record`","description":"If this notification provider is created in a plugin, the plugin's options are passed in this parameter.","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="new AbstractNotificationService"/> - -___ - -## Methods - -### sendNotification - -When an event is triggered that your Notification Provider is registered as a handler for, the [`NotificationService`](https://docs.medusajs.com/references/services/classes/services.NotificationService) -in the Medusa backend executes this method of your Notification Provider. - -In this method, you can perform the necessary operation to send the Notification. For example, you can send an email to the customer when they place an order. - -#### Example - -```ts -class EmailSenderService extends AbstractNotificationService { - // ... - async sendNotification( - event: string, - data: any, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - if (event === "order.placed") { - // retrieve order - const order = await this.orderService.retrieve(data.id) - // TODO send email - - console.log("Notification sent") - return { - to: order.email, - status: "done", - data: { - // any data necessary to send the email - // for example: - subject: "You placed a new order!", - items: order.items, - }, - } - } - } - // ... -} -``` - -#### Parameters - - - -#### Returns - -`","description":"The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object\nmight include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="sendNotification"/> - -### resendNotification - -This method is used to resend notifications, which is typically triggered by the -[Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications\_postnotificationsnotificationresend). - -#### Example - -```ts -class EmailSenderService extends AbstractNotificationService { - // ... - async resendNotification( - notification: any, - config: any, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - // check if the receiver should be changed - const to: string = config.to || notification.to - - // TODO resend the notification using the same data - // that is saved under notification.data - - console.log("Notification resent") - return { - to, - status: "done", - data: notification.data, // make changes to the data - } - } -} -``` - -#### Parameters - - - -#### Returns - -`","description":"The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object\nmight include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="resendNotification"/> - ---- - -## Subscribe with Loaders - -After creating your Notification Provider Service, you must create a [Loader](https://docs.medusajs.com/development/loaders/overview) that registers this Service as a notification handler of events. - -For example, to register the `email-sender` Notification Provider as a handler for the `order.placed` event, create the file `src/loaders/notification.ts` with the following content: - -```ts title="src/loaders/notification.ts" -import { - MedusaContainer, - NotificationService, -} from "@medusajs/medusa" - -export default async ( - container: MedusaContainer -): Promise => { - const notificationService = container.resolve< - NotificationService - >("notificationService") - - notificationService.subscribe( - "order.placed", - "email-sender" - ) -} -``` - -This loader accesses the `notificationService` through the [MedusaContainer](https://docs.medusajs.com/development/fundamentals/dependency-injection). The `notificationService` has a `subscribe` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that's subscribing to that event. - ---- - -## Test Sending a Notification - -Make sure you have an event bus module configured in your Medusa backend. You can learn more on how to do that in the [Configurations guide](https://docs.medusajs.com/development/backend/configurations#modules). - -Then: - -1\. Run the `build` command in the root directory of your Medusa backend: - -```bash npm2yarn -npm run build -``` - -2\. Start your Medusa backend: - -```bash npm2yarn -npx medusa develop -``` - -3\. Place an order either using the [REST APIs](https://docs.medusajs.com/api/store) or using the [storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). - -4\. After placing an order, you can see in your console the message “Notification Sent”. If you added your own notification sending logic, you should receive an email or alternatively the type of notification you’ve set up. - ---- - -## Test Resending a Notification - -To test resending a notification: - -1. Retrieve the ID of the notification you just sent using the [List Notifications API Route](https://docs.medusajs.com/api/admin#notifications_getnotifications). You can pass as a body parameter the `to` or `event_name` parameters to filter out the notification you just sent. - -2. Send a request to the [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend) using the ID retrieved from the previous request. You can pass the `to` parameter in the body to change the receiver of the notification. - -3. You should see the message “Notification Resent” in your console. diff --git a/www/apps/resources/references/notification/interfaces/notification.INotificationService/page.mdx b/www/apps/resources/references/notification/interfaces/notification.INotificationService/page.mdx deleted file mode 100644 index fe2c67170b..0000000000 --- a/www/apps/resources/references/notification/interfaces/notification.INotificationService/page.mdx +++ /dev/null @@ -1,224 +0,0 @@ -import { TypeList } from "docs-ui" - -# INotificationService - -## Overview - -:::note[Prerequisites] - -Before creating a Notification Provider, [install an event bus module](https://docs.medusajs.com/development/events/modules/redis). - -::: - -A Notification Provider is a provider that handles sending and resending of notifications. - -To create a Notification Provider, create a TypeScript or JavaScript file in `src/services`. The name of the file is the name of the provider -(for example, `sendgrid.ts`). The file must export a class that extends the `AbstractNotificationService` class imported from `@medusajs/medusa`. - -For example, create the file `src/services/email-sender.ts` with the following content: - -```ts title="src/services/email-sender.ts" -import { AbstractNotificationService } from "@medusajs/medusa" -import { EntityManager } from "typeorm" - -class EmailSenderService extends AbstractNotificationService { - protected manager_: EntityManager - protected transactionManager_: EntityManager - - sendNotification( - event: string, - data: unknown, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - throw new Error("Method not implemented.") - } - resendNotification( - notification: unknown, - config: unknown, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - throw new Error("Method not implemented.") - } - -} - -export default EmailSenderService -``` - ---- - -## Identifier Property - -The `NotificationProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the notification provider -class is used when the Notification Provider is created in the database. - -The value of this property is also used later when you want to subscribe the Notification Provider to events in a [Loader](https://docs.medusajs.com/development/loaders/overview). - -For example: - -```ts -class EmailSenderService extends AbstractNotificationService { - static identifier = "email-sender" - // ... -} -``` - ---- - -## Properties - -`","description":"","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"__moduleDeclaration__","type":"`Record`","description":"","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="INotificationService"/> - -___ - -## Accessors - -### activeManager\_ - -#### Returns - - - -___ - -## Methods - -### sendNotification - -When an event is triggered that your Notification Provider is registered as a handler for, the [`NotificationService`](https://docs.medusajs.com/references/services/classes/services.NotificationService) -in the Medusa backend executes this method of your Notification Provider. - -In this method, you can perform the necessary operation to send the Notification. For example, you can send an email to the customer when they place an order. - -#### Example - -```ts -class EmailSenderService extends AbstractNotificationService { - // ... - async sendNotification( - event: string, - data: any, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - if (event === "order.placed") { - // retrieve order - const order = await this.orderService.retrieve(data.id) - // TODO send email - - console.log("Notification sent") - return { - to: order.email, - status: "done", - data: { - // any data necessary to send the email - // for example: - subject: "You placed a new order!", - items: order.items, - }, - } - } - } - // ... -} -``` - -#### Parameters - - - -#### Returns - -`","description":"The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object\nmight include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="sendNotification"/> - -### resendNotification - -This method is used to resend notifications, which is typically triggered by the -[Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications\_postnotificationsnotificationresend). - -#### Example - -```ts -class EmailSenderService extends AbstractNotificationService { - // ... - async resendNotification( - notification: any, - config: any, - attachmentGenerator: unknown - ): Promise<{ - to: string; - status: string; - data: Record; - }> { - // check if the receiver should be changed - const to: string = config.to || notification.to - - // TODO resend the notification using the same data - // that is saved under notification.data - - console.log("Notification resent") - return { - to, - status: "done", - data: notification.data, // make changes to the data - } - } -} -``` - -#### Parameters - - - -#### Returns - -`","description":"The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object\nmight include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="resendNotification"/> - -### withTransaction - -#### Parameters - - - -#### Returns - - - -### shouldRetryTransaction\_ - -#### Parameters - -` \\| `object`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="shouldRetryTransaction_"/> - -#### Returns - - - -### atomicPhase\_ - -Wraps some work within a transactional block. If the service already has -a transaction manager attached this will be reused, otherwise a new -transaction manager is created. - -#### Type Parameters - - - -#### Parameters - - Promise<TResult>","description":"the transactional work to be done","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationOrErrorHandler","type":"`IsolationLevel` \\| (`error`: TError) => Promise<void \\| TResult>","description":"the isolation level to be used for the work.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"maybeErrorHandlerOrDontFail","type":"(`error`: TError) => Promise<void \\| TResult>","description":"Potential error handler","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="atomicPhase_"/> - -#### Returns - - diff --git a/www/apps/resources/references/notification/interfaces/notification.ReturnedData/page.mdx b/www/apps/resources/references/notification/interfaces/notification.ReturnedData/page.mdx deleted file mode 100644 index fb5a579467..0000000000 --- a/www/apps/resources/references/notification/interfaces/notification.ReturnedData/page.mdx +++ /dev/null @@ -1,9 +0,0 @@ -import { TypeList } from "docs-ui" - -# ReturnedData - -The details of a sent or resent notification. - -## Properties - -`","description":"The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object\nmight include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="ReturnedData"/> diff --git a/www/apps/resources/references/order/interfaces/order.UpdateOrderShippingMethodTaxLineDTO/page.mdx b/www/apps/resources/references/order/interfaces/order.UpdateOrderShippingMethodTaxLineDTO/page.mdx index 780a532a0c..7a5cab4761 100644 --- a/www/apps/resources/references/order/interfaces/order.UpdateOrderShippingMethodTaxLineDTO/page.mdx +++ b/www/apps/resources/references/order/interfaces/order.UpdateOrderShippingMethodTaxLineDTO/page.mdx @@ -4,6 +4,6 @@ displayed_sidebar: orderReference import { TypeList } from "docs-ui" -# UpdateOrderTaxLineDTO +# UpdateOrderShippingMethodTaxLineDTO - + diff --git a/www/apps/resources/references/order/interfaces/order.UpdateOrderTaxLineDTO/page.mdx b/www/apps/resources/references/order/interfaces/order.UpdateOrderTaxLineDTO/page.mdx index 7a5cab4761..780a532a0c 100644 --- a/www/apps/resources/references/order/interfaces/order.UpdateOrderTaxLineDTO/page.mdx +++ b/www/apps/resources/references/order/interfaces/order.UpdateOrderTaxLineDTO/page.mdx @@ -4,6 +4,6 @@ displayed_sidebar: orderReference import { TypeList } from "docs-ui" -# UpdateOrderShippingMethodTaxLineDTO +# UpdateOrderTaxLineDTO - + diff --git a/www/apps/resources/sidebar.mjs b/www/apps/resources/sidebar.mjs index 983d378c5e..c70a681028 100644 --- a/www/apps/resources/sidebar.mjs +++ b/www/apps/resources/sidebar.mjs @@ -1556,6 +1556,10 @@ export const sidebar = sidebarAttachHrefCommonOptions([ path: "/architectural-modules/file/local", title: "Local", }, + { + path: "/architectural-modules/file/s3", + title: "AWS S3 (and Compatible APIs)", + }, { title: "Guides", children: [ @@ -1568,6 +1572,35 @@ export const sidebar = sidebarAttachHrefCommonOptions([ ], }, { + path: "/architectural-modules/notification", + title: "Notification Provider Modules", + hasTitleStyling: true, + children: [ + { + path: "/architectural-modules/notification/local", + title: "Local", + }, + { + path: "/architectural-modules/notification/sendgrid", + title: "SendGrid", + }, + { + title: "Guides", + children: [ + { + path: "/architectural-modules/notification/send-notification", + title: "Send Notification", + }, + { + path: "/references/notification-provider-module", + title: "Create Notification Module", + }, + ], + }, + ], + }, + { + path: "/architectural-modules/workflow-engine", title: "Workflow Engine Modules", hasTitleStyling: true, children: [ diff --git a/www/utils/generated/typedoc-json-output/file.json b/www/utils/generated/typedoc-json-output/file.json index 9e67b20ce2..0d1cf4341a 100644 --- a/www/utils/generated/typedoc-json-output/file.json +++ b/www/utils/generated/typedoc-json-output/file.json @@ -1,19 +1,19 @@ { - "id": 0, + "id": 7, "name": "file", "variant": "project", "kind": 1, "flags": {}, "children": [ { - "id": 1, + "id": 8, "name": "AbstractFileProviderService", "variant": "declaration", "kind": 128, "flags": {}, "children": [ { - "id": 2, + "id": 9, "name": "identifier", "variant": "declaration", "kind": 1024, @@ -26,21 +26,21 @@ } }, { - "id": 3, + "id": 10, "name": "constructor", "variant": "declaration", "kind": 512, "flags": {}, "signatures": [ { - "id": 4, + "id": 11, "name": "new AbstractFileProviderService", "variant": "signature", "kind": 16384, "flags": {}, "type": { "type": "reference", - "target": 1, + "target": 8, "name": "AbstractFileProviderService", "package": "@medusajs/utils" } @@ -48,14 +48,14 @@ ] }, { - "id": 5, + "id": 12, "name": "getIdentifier", "variant": "declaration", "kind": 2048, "flags": {}, "signatures": [ { - "id": 6, + "id": 13, "name": "getIdentifier", "variant": "signature", "kind": 4096, @@ -68,21 +68,21 @@ ] }, { - "id": 7, + "id": 14, "name": "upload", "variant": "declaration", "kind": 2048, "flags": {}, "signatures": [ { - "id": 8, + "id": 15, "name": "upload", "variant": "signature", "kind": 4096, "flags": {}, "parameters": [ { - "id": 9, + "id": 16, "name": "file", "variant": "param", "kind": 32768, @@ -132,21 +132,21 @@ } }, { - "id": 10, + "id": 17, "name": "delete", "variant": "declaration", "kind": 2048, "flags": {}, "signatures": [ { - "id": 11, + "id": 18, "name": "delete", "variant": "signature", "kind": 4096, "flags": {}, "parameters": [ { - "id": 12, + "id": 19, "name": "file", "variant": "param", "kind": 32768, @@ -191,21 +191,21 @@ } }, { - "id": 13, + "id": 20, "name": "getPresignedDownloadUrl", "variant": "declaration", "kind": 2048, "flags": {}, "signatures": [ { - "id": 14, + "id": 21, "name": "getPresignedDownloadUrl", "variant": "signature", "kind": 4096, "flags": {}, "parameters": [ { - "id": 15, + "id": 22, "name": "fileData", "variant": "param", "kind": 32768, @@ -254,22 +254,22 @@ { "title": "Constructors", "children": [ - 3 + 10 ] }, { "title": "Properties", "children": [ - 2 + 9 ] }, { "title": "Methods", "children": [ - 5, - 7, - 10, - 13 + 12, + 14, + 17, + 20 ] } ], @@ -290,65 +290,65 @@ { "title": "Classes", "children": [ - 1 + 8 ] } ], "packageName": "@medusajs/utils", "symbolIdMap": { - "0": { + "7": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", "qualifiedName": "" }, - "1": { + "8": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", "qualifiedName": "AbstractFileProviderService" }, - "2": { + "9": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", "qualifiedName": "AbstractFileProviderService.identifier" }, - "5": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.getIdentifier" - }, - "6": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.getIdentifier" - }, - "7": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.upload" - }, - "8": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.upload" - }, - "9": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "file" - }, - "10": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.delete" - }, - "11": { - "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.delete" - }, "12": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "file" + "qualifiedName": "AbstractFileProviderService.getIdentifier" }, "13": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.getPresignedDownloadUrl" + "qualifiedName": "AbstractFileProviderService.getIdentifier" }, "14": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", - "qualifiedName": "AbstractFileProviderService.getPresignedDownloadUrl" + "qualifiedName": "AbstractFileProviderService.upload" }, "15": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "AbstractFileProviderService.upload" + }, + "16": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "file" + }, + "17": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "AbstractFileProviderService.delete" + }, + "18": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "AbstractFileProviderService.delete" + }, + "19": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "file" + }, + "20": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "AbstractFileProviderService.getPresignedDownloadUrl" + }, + "21": { + "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", + "qualifiedName": "AbstractFileProviderService.getPresignedDownloadUrl" + }, + "22": { "sourceFileName": "../../../../packages/core/utils/src/file/abstract-file-provider.ts", "qualifiedName": "fileData" } diff --git a/www/utils/generated/typedoc-json-output/notification.json b/www/utils/generated/typedoc-json-output/notification.json index 91217a3656..aeb6b490e5 100644 --- a/www/utils/generated/typedoc-json-output/notification.json +++ b/www/utils/generated/typedoc-json-output/notification.json @@ -1,1977 +1,67 @@ { - "id": 24090, + "id": 0, "name": "notification", "variant": "project", "kind": 1, "flags": {}, "children": [ { - "id": 24091, - "name": "ReturnedData", - "variant": "declaration", - "kind": 256, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The details of a sent or resent notification." - } - ] - }, - "children": [ - { - "id": 24092, - "name": "to", - "variant": "declaration", - "kind": 1024, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The receiver of the Notification. For example, if you sent an email to the customer then " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " is the email address of the customer.\nIn other cases, it might be a phone number or a username." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 24093, - "name": "status", - "variant": "declaration", - "kind": 1024, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The status of the sent notification. There are no restriction on the returned status." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 24094, - "name": "data", - "variant": "declaration", - "kind": 1024, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " object\nmight include the order items or the subject of the email. This " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " is necessary if the notification is resent later as you can use the same data." - } - ] - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - } - } - ], - "groups": [ - { - "title": "Properties", - "children": [ - 24092, - 24093, - 24094 - ] - } - ] - }, - { - "id": 24095, - "name": "INotificationService", - "variant": "declaration", - "kind": 256, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "## Overview\n\n:::note[Prerequisites]\n\nBefore creating a Notification Provider, [install an event bus module](https://docs.medusajs.com/development/events/modules/redis).\n\n:::\n\nA Notification Provider is a provider that handles sending and resending of notifications.\n\nTo create a Notification Provider, create a TypeScript or JavaScript file in " - }, - { - "kind": "code", - "text": "`src/services`" - }, - { - "kind": "text", - "text": ". The name of the file is the name of the provider\n(for example, " - }, - { - "kind": "code", - "text": "`sendgrid.ts`" - }, - { - "kind": "text", - "text": "). The file must export a class that extends the " - }, - { - "kind": "code", - "text": "`AbstractNotificationService`" - }, - { - "kind": "text", - "text": " class imported from " - }, - { - "kind": "code", - "text": "`@medusajs/medusa`" - }, - { - "kind": "text", - "text": ".\n\nFor example, create the file " - }, - { - "kind": "code", - "text": "`src/services/email-sender.ts`" - }, - { - "kind": "text", - "text": " with the following content:\n\n" - }, - { - "kind": "code", - "text": "```ts title=\"src/services/email-sender.ts\"\nimport { AbstractNotificationService } from \"@medusajs/medusa\"\nimport { EntityManager } from \"typeorm\"\n\nclass EmailSenderService extends AbstractNotificationService {\n protected manager_: EntityManager\n protected transactionManager_: EntityManager\n\n sendNotification(\n event: string,\n data: unknown,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n throw new Error(\"Method not implemented.\")\n }\n resendNotification(\n notification: unknown,\n config: unknown,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n throw new Error(\"Method not implemented.\")\n }\n\n}\n\nexport default EmailSenderService\n```" - }, - { - "kind": "text", - "text": "\n\n---\n\n## Identifier Property\n\nThe " - }, - { - "kind": "code", - "text": "`NotificationProvider`" - }, - { - "kind": "text", - "text": " entity has 2 properties: " - }, - { - "kind": "code", - "text": "`identifier`" - }, - { - "kind": "text", - "text": " and " - }, - { - "kind": "code", - "text": "`is_installed`" - }, - { - "kind": "text", - "text": ". The value of the " - }, - { - "kind": "code", - "text": "`identifier`" - }, - { - "kind": "text", - "text": " property in the notification provider\nclass is used when the Notification Provider is created in the database.\n\nThe value of this property is also used later when you want to subscribe the Notification Provider to events in a [Loader](https://docs.medusajs.com/development/loaders/overview).\n\nFor example:\n\n" - }, - { - "kind": "code", - "text": "```ts\nclass EmailSenderService extends AbstractNotificationService {\n static identifier = \"email-sender\"\n // ...\n}\n```" - }, - { - "kind": "text", - "text": "\n\n---" - } - ] - }, - "children": [ - { - "id": 24096, - "name": "sendNotification", - "variant": "declaration", - "kind": 2048, - "flags": {}, - "signatures": [ - { - "id": 24097, - "name": "sendNotification", - "variant": "signature", - "kind": 4096, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "When an event is triggered that your Notification Provider is registered as a handler for, the [" - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService)\nin the Medusa backend executes this method of your Notification Provider.\n\nIn this method, you can perform the necessary operation to send the Notification. For example, you can send an email to the customer when they place an order." - } - ], - "blockTags": [ - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "The sending details." - } - ] - }, - { - "tag": "@example", - "content": [ - { - "kind": "code", - "text": "```ts\nclass EmailSenderService extends AbstractNotificationService {\n // ...\n async sendNotification(\n event: string,\n data: any,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n if (event === \"order.placed\") {\n // retrieve order\n const order = await this.orderService.retrieve(data.id)\n // TODO send email\n\n console.log(\"Notification sent\")\n return {\n to: order.email,\n status: \"done\",\n data: {\n // any data necessary to send the email\n // for example:\n subject: \"You placed a new order!\",\n items: order.items,\n },\n }\n }\n }\n // ...\n}\n```" - } - ] - } - ] - }, - "parameters": [ - { - "id": 24098, - "name": "event", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The name of the event that was triggered. For example, " - }, - { - "kind": "code", - "text": "`order.placed`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 24099, - "name": "data", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The data payload of the event that was triggered. For example, if the " - }, - { - "kind": "code", - "text": "`order.placed`" - }, - { - "kind": "text", - "text": " event is triggered,\nthe " - }, - { - "kind": "code", - "text": "`eventData`" - }, - { - "kind": "text", - "text": " object contains the property " - }, - { - "kind": "code", - "text": "`id`" - }, - { - "kind": "text", - "text": " which is the ID of the order that was placed. You can refer to the\n[Events reference](https://docs.medusajs.com/development/events/events-list) for information on all events and their payloads." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24100, - "name": "attachmentGenerator", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "If you’ve previously register an attachment generator to the " - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": " using the\n[" - }, - { - "kind": "code", - "text": "`registerAttachmentGenerator`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method,\nyou have access to it here. You can use the " - }, - { - "kind": "code", - "text": "`attachmentGenerator`" - }, - { - "kind": "text", - "text": " to generate on-demand invoices or other documents. The default value of this parameter is " - }, - { - "kind": "code", - "text": "`null`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "reference", - "target": 24091, - "name": "ReturnedData", - "package": "@medusajs/medusa" - } - ], - "name": "Promise", - "package": "typescript" - } - } - ] - }, - { - "id": 24101, - "name": "resendNotification", - "variant": "declaration", - "kind": 2048, - "flags": {}, - "signatures": [ - { - "id": 24102, - "name": "resendNotification", - "variant": "signature", - "kind": 4096, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "This method is used to resend notifications, which is typically triggered by the\n[Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend)." - } - ], - "blockTags": [ - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "The resend details." - } - ] - }, - { - "tag": "@example", - "content": [ - { - "kind": "code", - "text": "```ts\nclass EmailSenderService extends AbstractNotificationService {\n // ...\n async resendNotification(\n notification: any,\n config: any,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n // check if the receiver should be changed\n const to: string = config.to || notification.to\n\n // TODO resend the notification using the same data\n // that is saved under notification.data\n\n console.log(\"Notification resent\")\n return {\n to,\n status: \"done\",\n data: notification.data, // make changes to the data\n }\n }\n}\n```" - } - ] - } - ] - }, - "parameters": [ - { - "id": 24103, - "name": "notification", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The original [Notification record](https://docs.medusajs.com/references/entities/classes/Notification) that was created after you sent the\nnotification with " - }, - { - "kind": "code", - "text": "`sendNotification`" - }, - { - "kind": "text", - "text": ". It includes the " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " and " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " attributes which are populated originally using the " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " and " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " properties of\nthe object you return in " - }, - { - "kind": "inline-tag", - "tag": "@link", - "text": "sendNotification", - "target": 24096, - "tsLinkText": "" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24104, - "name": "config", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The new configuration used to resend the notification. The [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend),\nallows you to pass a new " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " field. If specified, it will be available in this config object." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24105, - "name": "attachmentGenerator", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "f you’ve previously register an attachment generator to the " - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": " using the\n[" - }, - { - "kind": "code", - "text": "`registerAttachmentGenerator`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method,\nyou have access to it here. You can use the " - }, - { - "kind": "code", - "text": "`attachmentGenerator`" - }, - { - "kind": "text", - "text": " to generate on-demand invoices or other documents. The default value of this parameter is " - }, - { - "kind": "code", - "text": "`null`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "reference", - "target": 24091, - "name": "ReturnedData", - "package": "@medusajs/medusa" - } - ], - "name": "Promise", - "package": "typescript" - } - } - ] - }, - { - "id": 24106, - "name": "manager_", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.manager_" - } - }, - { - "id": 24107, - "name": "transactionManager_", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "undefined" - }, - { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - } - ] - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.transactionManager_" - } - }, - { - "id": 24108, - "name": "activeManager_", - "variant": "declaration", - "kind": 262144, - "flags": { - "isProtected": true - }, - "getSignature": { - "id": 24109, - "name": "activeManager_", - "variant": "signature", - "kind": 524288, - "flags": {}, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.activeManager_" - } - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.activeManager_" - } - }, - { - "id": 24110, - "name": "__container__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isReadonly": true - }, - "type": { - "type": "intrinsic", - "name": "any" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__container__" - } - }, - { - "id": 24111, - "name": "__configModule__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isOptional": true, - "isReadonly": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__configModule__" - } - }, - { - "id": 24112, - "name": "__moduleDeclaration__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isOptional": true, - "isReadonly": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__moduleDeclaration__" - } - }, - { - "id": 24113, - "name": "withTransaction", - "variant": "declaration", - "kind": 2048, - "flags": {}, - "signatures": [ - { - "id": 24114, - "name": "withTransaction", - "variant": "signature", - "kind": 4096, - "flags": {}, - "parameters": [ - { - "id": 24115, - "name": "transactionManager", - "variant": "param", - "kind": 32768, - "flags": { - "isOptional": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - } - } - ], - "type": { - "type": "intrinsic", - "name": "this" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.withTransaction" - } - } - ], - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.withTransaction" - } - }, - { - "id": 24116, - "name": "shouldRetryTransaction_", - "variant": "declaration", - "kind": 2048, - "flags": { - "isProtected": true - }, - "signatures": [ - { - "id": 24117, - "name": "shouldRetryTransaction_", - "variant": "signature", - "kind": 4096, - "flags": {}, - "parameters": [ - { - "id": 24118, - "name": "err", - "variant": "param", - "kind": 32768, - "flags": {}, - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - }, - { - "type": "reflection", - "declaration": { - "id": 24119, - "name": "__type", - "variant": "declaration", - "kind": 65536, - "flags": {}, - "children": [ - { - "id": 24120, - "name": "code", - "variant": "declaration", - "kind": 1024, - "flags": {}, - "type": { - "type": "intrinsic", - "name": "string" - } - } - ], - "groups": [ - { - "title": "Properties", - "children": [ - 24120 - ] - } - ] - } - } - ] - } - } - ], - "type": { - "type": "intrinsic", - "name": "boolean" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.shouldRetryTransaction_" - } - } - ], - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.shouldRetryTransaction_" - } - }, - { - "id": 24121, - "name": "atomicPhase_", - "variant": "declaration", - "kind": 2048, - "flags": { - "isProtected": true - }, - "signatures": [ - { - "id": 24122, - "name": "atomicPhase_", - "variant": "signature", - "kind": 4096, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "Wraps some work within a transactional block. If the service already has\na transaction manager attached this will be reused, otherwise a new\ntransaction manager is created." - } - ], - "blockTags": [ - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "the result of the transactional work" - } - ] - } - ] - }, - "typeParameter": [ - { - "id": 24123, - "name": "TResult", - "variant": "typeParam", - "kind": 131072, - "flags": {} - }, - { - "id": 24124, - "name": "TError", - "variant": "typeParam", - "kind": 131072, - "flags": {} - } - ], - "parameters": [ - { - "id": 24125, - "name": "work", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "the transactional work to be done" - } - ] - }, - "type": { - "type": "reflection", - "declaration": { - "id": 24126, - "name": "__type", - "variant": "declaration", - "kind": 65536, - "flags": {}, - "signatures": [ - { - "id": 24127, - "name": "__type", - "variant": "signature", - "kind": 4096, - "flags": {}, - "parameters": [ - { - "id": 24128, - "name": "transactionManager", - "variant": "param", - "kind": 32768, - "flags": {}, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "reference", - "target": 24123, - "name": "TResult", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - ], - "name": "Promise", - "package": "typescript" - } - } - ] - } - } - }, - { - "id": 24129, - "name": "isolationOrErrorHandler", - "variant": "param", - "kind": 32768, - "flags": { - "isOptional": true - }, - "comment": { - "summary": [ - { - "kind": "text", - "text": "the isolation level to be used for the work." - } - ] - }, - "type": { - "type": "union", - "types": [ - { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/driver/types/IsolationLevel.d.ts", - "qualifiedName": "IsolationLevel" - }, - "name": "IsolationLevel", - "package": "typeorm" - }, - { - "type": "reflection", - "declaration": { - "id": 24130, - "name": "__type", - "variant": "declaration", - "kind": 65536, - "flags": {}, - "signatures": [ - { - "id": 24131, - "name": "__type", - "variant": "signature", - "kind": 4096, - "flags": {}, - "parameters": [ - { - "id": 24132, - "name": "error", - "variant": "param", - "kind": 32768, - "flags": {}, - "type": { - "type": "reference", - "target": 24124, - "name": "TError", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "void" - }, - { - "type": "reference", - "target": 24123, - "name": "TResult", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - ] - } - ], - "name": "Promise", - "package": "typescript" - } - } - ] - } - } - ] - } - }, - { - "id": 24133, - "name": "maybeErrorHandlerOrDontFail", - "variant": "param", - "kind": 32768, - "flags": { - "isOptional": true - }, - "comment": { - "summary": [ - { - "kind": "text", - "text": "Potential error handler" - } - ] - }, - "type": { - "type": "reflection", - "declaration": { - "id": 24134, - "name": "__type", - "variant": "declaration", - "kind": 65536, - "flags": {}, - "signatures": [ - { - "id": 24135, - "name": "__type", - "variant": "signature", - "kind": 4096, - "flags": {}, - "parameters": [ - { - "id": 24136, - "name": "error", - "variant": "param", - "kind": 32768, - "flags": {}, - "type": { - "type": "reference", - "target": 24124, - "name": "TError", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "void" - }, - { - "type": "reference", - "target": 24123, - "name": "TResult", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - ] - } - ], - "name": "Promise", - "package": "typescript" - } - } - ] - } - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "reference", - "target": 24123, - "name": "TResult", - "package": "@medusajs/medusa", - "refersToTypeParameter": true - } - ], - "name": "Promise", - "package": "typescript" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.atomicPhase_" - } - } - ], - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.atomicPhase_" - } - } - ], - "groups": [ - { - "title": "Properties", - "children": [ - 24106, - 24107, - 24110, - 24111, - 24112 - ] - }, - { - "title": "Accessors", - "children": [ - 24108 - ] - }, - { - "title": "Methods", - "children": [ - 24096, - 24101, - 24113, - 24116, - 24121 - ] - } - ], - "extendedTypes": [ - { - "type": "reference", - "target": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService" - }, - "name": "TransactionBaseService", - "package": "@medusajs/medusa" - } - ], - "implementedBy": [ - { - "type": "reference", - "target": 24137, - "name": "AbstractNotificationService" - } - ] - }, - { - "id": 24137, - "name": "AbstractNotificationService", + "id": 1, + "name": "AbstractNotificationProviderService", "variant": "declaration", "kind": 128, - "flags": { - "isAbstract": true - }, + "flags": {}, "children": [ { - "id": 24139, - "name": "identifier", - "variant": "declaration", - "kind": 1024, - "flags": { - "isStatic": true - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 24143, + "id": 2, "name": "constructor", "variant": "declaration", "kind": 512, - "flags": { - "isProtected": true - }, + "flags": {}, "signatures": [ { - "id": 24144, - "name": "new AbstractNotificationService", + "id": 3, + "name": "new AbstractNotificationProviderService", "variant": "signature", "kind": 16384, "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "You can use the " - }, - { - "kind": "code", - "text": "`constructor`" - }, - { - "kind": "text", - "text": " of your notification provider to access the different services in Medusa through dependency injection.\n\nYou can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs,\nyou can initialize it in the constructor and use it in other methods in the service.\n\nAdditionally, if you’re creating your notification provider as an external plugin to be installed on any Medusa backend and you want to access the options\nadded for the plugin, you can access it in the constructor." - } - ], - "blockTags": [ - { - "tag": "@example", - "content": [ - { - "kind": "code", - "text": "```ts\n// ...\nimport { AbstractNotificationService, OrderService } from \"@medusajs/medusa\"\nimport { EntityManager } from \"typeorm\"\n\nclass EmailSenderService extends AbstractNotificationService {\n // ...\n protected orderService: OrderService\n\n constructor(container, options) {\n super(container)\n // you can access options here in case you're\n // using a plugin\n\n this.orderService = container.orderService\n\n // you can also initialize a client that\n // communicates with a third-party service.\n this.client = new Client(options)\n }\n\n // ...\n}\n\nexport default EmailSenderService\n```" - } - ] - } - ] - }, - "parameters": [ - { - "id": 24145, - "name": "container", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "An instance of " - }, - { - "kind": "code", - "text": "`MedusaContainer`" - }, - { - "kind": "text", - "text": " that allows you to access other resources, such as services, in your Medusa backend." - } - ] - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - } - }, - { - "id": 24146, - "name": "config", - "variant": "param", - "kind": 32768, - "flags": { - "isOptional": true - }, - "comment": { - "summary": [ - { - "kind": "text", - "text": "If this notification provider is created in a plugin, the plugin's options are passed in this parameter." - } - ] - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - } - } - ], "type": { "type": "reference", - "target": 24137, - "name": "AbstractNotificationService", - "package": "@medusajs/medusa" - }, - "overwrites": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.constructor" + "target": 1, + "name": "AbstractNotificationProviderService", + "package": "@medusajs/utils" } } - ], - "overwrites": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.constructor" - } + ] }, { - "id": 24149, - "name": "container", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isReadonly": true - }, - "comment": { - "summary": [ - { - "kind": "text", - "text": "An instance of " - }, - { - "kind": "code", - "text": "`MedusaContainer`" - }, - { - "kind": "text", - "text": " that allows you to access other resources, such as services, in your Medusa backend." - } - ] - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - } - }, - { - "id": 24150, - "name": "config", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isOptional": true, - "isReadonly": true - }, - "comment": { - "summary": [ - { - "kind": "text", - "text": "If this notification provider is created in a plugin, the plugin's options are passed in this parameter." - } - ] - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - } - }, - { - "id": 24151, - "name": "sendNotification", + "id": 4, + "name": "send", "variant": "declaration", "kind": 2048, - "flags": { - "isAbstract": true - }, + "flags": {}, "signatures": [ { - "id": 24152, - "name": "sendNotification", + "id": 5, + "name": "send", "variant": "signature", "kind": 4096, "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "When an event is triggered that your Notification Provider is registered as a handler for, the [" - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService)\nin the Medusa backend executes this method of your Notification Provider.\n\nIn this method, you can perform the necessary operation to send the Notification. For example, you can send an email to the customer when they place an order." - } - ], - "blockTags": [ - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "The sending details." - } - ] - }, - { - "tag": "@example", - "content": [ - { - "kind": "code", - "text": "```ts\nclass EmailSenderService extends AbstractNotificationService {\n // ...\n async sendNotification(\n event: string,\n data: any,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n if (event === \"order.placed\") {\n // retrieve order\n const order = await this.orderService.retrieve(data.id)\n // TODO send email\n\n console.log(\"Notification sent\")\n return {\n to: order.email,\n status: \"done\",\n data: {\n // any data necessary to send the email\n // for example:\n subject: \"You placed a new order!\",\n items: order.items,\n },\n }\n }\n }\n // ...\n}\n```" - } - ] - } - ] - }, "parameters": [ { - "id": 24153, - "name": "event", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The name of the event that was triggered. For example, " - }, - { - "kind": "code", - "text": "`order.placed`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "string" - } - }, - { - "id": 24154, - "name": "data", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The data payload of the event that was triggered. For example, if the " - }, - { - "kind": "code", - "text": "`order.placed`" - }, - { - "kind": "text", - "text": " event is triggered,\nthe " - }, - { - "kind": "code", - "text": "`eventData`" - }, - { - "kind": "text", - "text": " object contains the property " - }, - { - "kind": "code", - "text": "`id`" - }, - { - "kind": "text", - "text": " which is the ID of the order that was placed. You can refer to the\n[Events reference](https://docs.medusajs.com/development/events/events-list) for information on all events and their payloads." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24155, - "name": "attachmentGenerator", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "If you’ve previously register an attachment generator to the " - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": " using the\n[" - }, - { - "kind": "code", - "text": "`registerAttachmentGenerator`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method,\nyou have access to it here. You can use the " - }, - { - "kind": "code", - "text": "`attachmentGenerator`" - }, - { - "kind": "text", - "text": " to generate on-demand invoices or other documents. The default value of this parameter is " - }, - { - "kind": "code", - "text": "`null`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - } - ], - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Promise" - }, - "typeArguments": [ - { - "type": "reference", - "target": 24091, - "name": "ReturnedData", - "package": "@medusajs/medusa" - } - ], - "name": "Promise", - "package": "typescript" - }, - "implementationOf": { - "type": "reference", - "target": 24097, - "name": "INotificationService.sendNotification" - } - } - ], - "implementationOf": { - "type": "reference", - "target": 24096, - "name": "INotificationService.sendNotification" - } - }, - { - "id": 24156, - "name": "resendNotification", - "variant": "declaration", - "kind": 2048, - "flags": { - "isAbstract": true - }, - "signatures": [ - { - "id": 24157, - "name": "resendNotification", - "variant": "signature", - "kind": 4096, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "This method is used to resend notifications, which is typically triggered by the\n[Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend)." - } - ], - "blockTags": [ - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "The resend details." - } - ] - }, - { - "tag": "@example", - "content": [ - { - "kind": "code", - "text": "```ts\nclass EmailSenderService extends AbstractNotificationService {\n // ...\n async resendNotification(\n notification: any,\n config: any,\n attachmentGenerator: unknown\n ): Promise<{\n to: string;\n status: string;\n data: Record;\n }> {\n // check if the receiver should be changed\n const to: string = config.to || notification.to\n\n // TODO resend the notification using the same data\n // that is saved under notification.data\n\n console.log(\"Notification resent\")\n return {\n to,\n status: \"done\",\n data: notification.data, // make changes to the data\n }\n }\n}\n```" - } - ] - } - ] - }, - "parameters": [ - { - "id": 24158, + "id": 6, "name": "notification", "variant": "param", "kind": 32768, "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The original [Notification record](https://docs.medusajs.com/references/entities/classes/Notification) that was created after you sent the\nnotification with " - }, - { - "kind": "code", - "text": "`sendNotification`" - }, - { - "kind": "text", - "text": ". It includes the " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " and " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " attributes which are populated originally using the " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " and " - }, - { - "kind": "code", - "text": "`data`" - }, - { - "kind": "text", - "text": " properties of\nthe object you return in " - }, - { - "kind": "inline-tag", - "tag": "@link", - "text": "sendNotification", - "target": 24096, - "tsLinkText": "" - }, - { - "kind": "text", - "text": "." - } - ] - }, "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24159, - "name": "config", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "The new configuration used to resend the notification. The [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend),\nallows you to pass a new " - }, - { - "kind": "code", - "text": "`to`" - }, - { - "kind": "text", - "text": " field. If specified, it will be available in this config object." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" - } - }, - { - "id": 24160, - "name": "attachmentGenerator", - "variant": "param", - "kind": 32768, - "flags": {}, - "comment": { - "summary": [ - { - "kind": "text", - "text": "f you’ve previously register an attachment generator to the " - }, - { - "kind": "code", - "text": "`NotificationService`" - }, - { - "kind": "text", - "text": " using the\n[" - }, - { - "kind": "code", - "text": "`registerAttachmentGenerator`" - }, - { - "kind": "text", - "text": "](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method,\nyou have access to it here. You can use the " - }, - { - "kind": "code", - "text": "`attachmentGenerator`" - }, - { - "kind": "text", - "text": " to generate on-demand invoices or other documents. The default value of this parameter is " - }, - { - "kind": "code", - "text": "`null`" - }, - { - "kind": "text", - "text": "." - } - ] - }, - "type": { - "type": "intrinsic", - "name": "unknown" + "type": "reference", + "target": { + "sourceFileName": "../../../../packages/core/types/src/notification/provider.ts", + "qualifiedName": "ProviderSendNotificationDTO" + }, + "name": "ProviderSendNotificationDTO", + "package": "@medusajs/types" } } ], @@ -1984,9 +74,12 @@ "typeArguments": [ { "type": "reference", - "target": 24091, - "name": "ReturnedData", - "package": "@medusajs/medusa" + "target": { + "sourceFileName": "../../../../packages/core/types/src/notification/provider.ts", + "qualifiedName": "ProviderSendNotificationResultsDTO" + }, + "name": "ProviderSendNotificationResultsDTO", + "package": "@medusajs/types" } ], "name": "Promise", @@ -1994,184 +87,15 @@ }, "implementationOf": { "type": "reference", - "target": 24102, - "name": "INotificationService.resendNotification" + "target": -1, + "name": "INotificationProvider.send" } } ], "implementationOf": { - "type": "reference", - "target": 24101, - "name": "INotificationService.resendNotification" - } - }, - { - "id": 24161, - "name": "manager_", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - }, - "inheritedFrom": { "type": "reference", "target": -1, - "name": "TransactionBaseService.manager_" - }, - "implementationOf": { - "type": "reference", - "target": 24106, - "name": "INotificationService.manager_" - } - }, - { - "id": 24162, - "name": "transactionManager_", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true - }, - "type": { - "type": "union", - "types": [ - { - "type": "intrinsic", - "name": "undefined" - }, - { - "type": "reference", - "target": { - "sourceFileName": "../../../node_modules/typeorm/entity-manager/EntityManager.d.ts", - "qualifiedName": "EntityManager" - }, - "name": "EntityManager", - "package": "typeorm" - } - ] - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.transactionManager_" - }, - "implementationOf": { - "type": "reference", - "target": 24107, - "name": "INotificationService.transactionManager_" - } - }, - { - "id": 24165, - "name": "__container__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isReadonly": true - }, - "type": { - "type": "intrinsic", - "name": "any" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__container__" - }, - "implementationOf": { - "type": "reference", - "target": 24110, - "name": "INotificationService.__container__" - } - }, - { - "id": 24166, - "name": "__configModule__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isOptional": true, - "isReadonly": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__configModule__" - }, - "implementationOf": { - "type": "reference", - "target": 24111, - "name": "INotificationService.__configModule__" - } - }, - { - "id": 24167, - "name": "__moduleDeclaration__", - "variant": "declaration", - "kind": 1024, - "flags": { - "isProtected": true, - "isOptional": true, - "isReadonly": true - }, - "type": { - "type": "reference", - "target": { - "sourceFileName": "../../node_modules/typescript/lib/lib.es5.d.ts", - "qualifiedName": "Record" - }, - "typeArguments": [ - { - "type": "intrinsic", - "name": "string" - }, - { - "type": "intrinsic", - "name": "unknown" - } - ], - "name": "Record", - "package": "typescript" - }, - "inheritedFrom": { - "type": "reference", - "target": -1, - "name": "TransactionBaseService.__moduleDeclaration__" - }, - "implementationOf": { - "type": "reference", - "target": 24112, - "name": "INotificationService.__moduleDeclaration__" + "name": "INotificationProvider.send" } } ], @@ -2179,47 +103,25 @@ { "title": "Constructors", "children": [ - 24143 - ] - }, - { - "title": "Properties", - "children": [ - 24139, - 24149, - 24150, - 24161, - 24162, - 24165, - 24166, - 24167 + 2 ] }, { "title": "Methods", "children": [ - 24151, - 24156 + 4 ] } ], - "extendedTypes": [ - { - "type": "reference", - "target": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService" - }, - "name": "TransactionBaseService", - "package": "@medusajs/medusa" - } - ], "implementedTypes": [ { "type": "reference", - "target": 24095, - "name": "INotificationService", - "package": "@medusajs/medusa" + "target": { + "sourceFileName": "../../../../packages/core/types/src/notification/provider.ts", + "qualifiedName": "INotificationProvider" + }, + "name": "INotificationProvider", + "package": "@medusajs/types" } ] } @@ -2228,402 +130,31 @@ { "title": "Classes", "children": [ - 24137 - ] - }, - { - "title": "Interfaces", - "children": [ - 24091, - 24095 + 1 ] } ], - "packageName": "@medusajs/medusa", + "packageName": "@medusajs/utils", "symbolIdMap": { - "24090": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", + "0": { + "sourceFileName": "../../../../packages/core/utils/src/notification/abstract-notification-provider.ts", "qualifiedName": "" }, - "24091": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "ReturnedData" + "1": { + "sourceFileName": "../../../../packages/core/utils/src/notification/abstract-notification-provider.ts", + "qualifiedName": "AbstractNotificationProviderService" }, - "24092": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "__type.to" + "4": { + "sourceFileName": "../../../../packages/core/utils/src/notification/abstract-notification-provider.ts", + "qualifiedName": "AbstractNotificationProviderService.send" }, - "24093": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "__type.status" + "5": { + "sourceFileName": "../../../../packages/core/utils/src/notification/abstract-notification-provider.ts", + "qualifiedName": "AbstractNotificationProviderService.send" }, - "24094": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "__type.data" - }, - "24095": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "INotificationService" - }, - "24096": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "INotificationService.sendNotification" - }, - "24097": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "INotificationService.sendNotification" - }, - "24098": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "event" - }, - "24099": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "data" - }, - "24100": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "attachmentGenerator" - }, - "24101": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "INotificationService.resendNotification" - }, - "24102": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "INotificationService.resendNotification" - }, - "24103": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", + "6": { + "sourceFileName": "../../../../packages/core/utils/src/notification/abstract-notification-provider.ts", "qualifiedName": "notification" - }, - "24104": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "config" - }, - "24105": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "attachmentGenerator" - }, - "24106": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.manager_" - }, - "24107": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.transactionManager_" - }, - "24108": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.activeManager_" - }, - "24109": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.activeManager_" - }, - "24110": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__container__" - }, - "24111": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__configModule__" - }, - "24112": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__moduleDeclaration__" - }, - "24113": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.withTransaction" - }, - "24114": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.withTransaction" - }, - "24115": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "transactionManager" - }, - "24116": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.shouldRetryTransaction_" - }, - "24117": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.shouldRetryTransaction_" - }, - "24118": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "err" - }, - "24119": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24120": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type.code" - }, - "24121": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.atomicPhase_" - }, - "24122": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.atomicPhase_" - }, - "24123": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TResult" - }, - "24124": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TError" - }, - "24125": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "work" - }, - "24126": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24127": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24128": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "transactionManager" - }, - "24129": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "isolationOrErrorHandler" - }, - "24130": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24131": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24132": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "error" - }, - "24133": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "maybeErrorHandlerOrDontFail" - }, - "24134": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24135": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24136": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "error" - }, - "24137": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService" - }, - "24139": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.identifier" - }, - "24143": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.__constructor" - }, - "24144": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService" - }, - "24145": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "container" - }, - "24146": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "config" - }, - "24149": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.container" - }, - "24150": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.config" - }, - "24151": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.sendNotification" - }, - "24152": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.sendNotification" - }, - "24153": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "event" - }, - "24154": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "data" - }, - "24155": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "attachmentGenerator" - }, - "24156": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.resendNotification" - }, - "24157": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "AbstractNotificationService.resendNotification" - }, - "24158": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "notification" - }, - "24159": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "config" - }, - "24160": { - "sourceFileName": "../../../packages/medusa/src/interfaces/notification-service.ts", - "qualifiedName": "attachmentGenerator" - }, - "24161": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.manager_" - }, - "24162": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.transactionManager_" - }, - "24163": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.activeManager_" - }, - "24164": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.activeManager_" - }, - "24165": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__container__" - }, - "24166": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__configModule__" - }, - "24167": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.__moduleDeclaration__" - }, - "24168": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.withTransaction" - }, - "24169": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.withTransaction" - }, - "24170": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "transactionManager" - }, - "24171": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.shouldRetryTransaction_" - }, - "24172": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.shouldRetryTransaction_" - }, - "24173": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "err" - }, - "24174": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24175": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type.code" - }, - "24176": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.atomicPhase_" - }, - "24177": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TransactionBaseService.atomicPhase_" - }, - "24178": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TResult" - }, - "24179": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "TError" - }, - "24180": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "work" - }, - "24181": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24182": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24183": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "transactionManager" - }, - "24184": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "isolationOrErrorHandler" - }, - "24185": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24186": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24187": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "error" - }, - "24188": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "maybeErrorHandlerOrDontFail" - }, - "24189": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24190": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "__type" - }, - "24191": { - "sourceFileName": "../../../packages/medusa/src/interfaces/transaction-base-service.ts", - "qualifiedName": "error" } } } \ No newline at end of file diff --git a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts index 46d26fc743..83bd11c6fd 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts @@ -78,8 +78,9 @@ const customOptions: Record> = { ], }), notification: getOptions({ - entryPointPath: "packages/medusa/src/interfaces/notification-service.ts", - tsConfigName: "medusa.json", + entryPointPath: + "packages/core/utils/src/notification/abstract-notification-provider.ts", + tsConfigName: "utils.json", name: "notification", parentIgnore: true, }), diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/file.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/file.ts index f07286f567..cdf034204a 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/file.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/file.ts @@ -64,26 +64,27 @@ The File Module accepts one provider only. \`\`\`js title="medusa-config.js" -module.exports = { +const { Modules } = require("@medusajs/modules-sdk") + +// ... + +const modules = { // ... - modules: { - // ... - [Modules.FILE]: { - resolve: "@medusajs/file", - options: { - providers: [ - { - resolve: "./dist/modules/my-file", - options: { - config: { - "my-file": { - // provider options... - }, + [Modules.FILE]: { + resolve: "@medusajs/file", + options: { + providers: [ + { + resolve: "./dist/modules/my-file", + options: { + config: { + "my-file": { + // provider options... }, }, }, - ], - }, + }, + ], }, }, } diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/notification.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/notification.ts index aa00648b47..a0c0b4ec03 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/notification.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/notification.ts @@ -1,76 +1,98 @@ import { FormattingOptionsType } from "types" const notificationOptions: FormattingOptionsType = { - "^notification/.*AbstractNotificationService": { + "^notification": { + frontmatterData: { + displayed_sidebar: "core", + }, + }, + "^notification/.*AbstractNotificationProviderService": { reflectionGroups: { Properties: false, }, - reflectionDescription: `In this document, you’ll learn how to create a notification provider in the Medusa backend and the methods you must implement in it. Learn more about the notification architecture in [this documentation](https://docs.medusajs.com/development/notification/overview)`, + reflectionDescription: `In this document, you’ll learn how to create a notification provider module and the methods you must implement in it.`, frontmatterData: { - slug: "/references/notification-service", + slug: "/references/notification-provider-module", }, reflectionTitle: { - fullReplacement: "How to Create a Notification Provider", + fullReplacement: "How to Create a Notification Provider Module", }, - endSections: [ - `## Subscribe with Loaders + shouldIncrementAfterStartSections: true, + expandMembers: true, + startSections: [ + `## 1. Create Module Directory -After creating your Notification Provider Service, you must create a [Loader](https://docs.medusajs.com/development/loaders/overview) that registers this Service as a notification handler of events. +Start by creating a new directory for your module. For example, \`src/modules/my-notification\`.`, + `## 2. Create the Notification Provider Service -For example, to register the \`email-sender\` Notification Provider as a handler for the \`order.placed\` event, create the file \`src/loaders/notification.ts\` with the following content: +Create the file \`src/modules/my-notification/service.ts\` that holds the implementation of the notification service. -\`\`\`ts title="src/loaders/notification.ts" +The Notification Provider Module's main service must extend the \`AbstractNotificationProviderService\` class imported from \`@medusajs/utils\`: + +\`\`\`ts title="src/modules/my-notification/service.ts" import { - MedusaContainer, - NotificationService, -} from "@medusajs/medusa" + AbstractNotificationProviderService +} from "@medusajs/utils" -export default async ( - container: MedusaContainer -): Promise => { - const notificationService = container.resolve< - NotificationService - >("notificationService") +class MyNotificationProviderService extends AbstractNotificationProviderService { + // TODO add methods +} - notificationService.subscribe( - "order.placed", - "email-sender" - ) +export default MyNotificationProviderService +\`\`\``, + ], + endSections: [ + `## 3. Create Module Definition File + +Create the file \`src/modules/my-notification/index.ts\` with the following content: + +\`\`\`ts title="src/modules/my-notification/index.ts" +import MyNotificationProviderService from "./service" + +export default { + service: MyNotificationProviderService, } \`\`\` -This loader accesses the \`notificationService\` through the [MedusaContainer](https://docs.medusajs.com/development/fundamentals/dependency-injection). The \`notificationService\` has a \`subscribe\` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that's subscribing to that event.`, - `## Test Sending a Notification +This exports the module's definition, indicating that the \`MyNotificationProviderService\` is the main service of the module.`, + `## 4. Use Module -Make sure you have an event bus module configured in your Medusa backend. You can learn more on how to do that in the [Configurations guide](https://docs.medusajs.com/development/backend/configurations#modules). +To use your Notification Provider Module, add it to the \`providers\` array of the Notification Module: -Then: + -1\\. Run the \`build\` command in the root directory of your Medusa backend: +The Notification Module accepts one provider per channel. -\`\`\`bash npm2yarn -npm run build + + +\`\`\`js title="medusa-config.js" +const { Modules } = require("@medusajs/modules-sdk") + +// ... + +const modules = { + // ... + [Modules.NOTIFICATION]: { + resolve: "@medusajs/notification", + options: { + providers: [ + { + resolve: "./dist/modules/my-notification", + options: { + config: { + "my-notification": { + channels: ["email"], + // provider options... + }, + }, + }, + }, + ], + }, + }, +} \`\`\` - -2\\. Start your Medusa backend: - -\`\`\`bash npm2yarn -npx medusa develop -\`\`\` - -3\\. Place an order either using the [REST APIs](https://docs.medusajs.com/api/store) or using the [storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). - -4\\. After placing an order, you can see in your console the message “Notification Sent”. If you added your own notification sending logic, you should receive an email or alternatively the type of notification you’ve set up.`, - `## Test Resending a Notification - -To test resending a notification: - -1. Retrieve the ID of the notification you just sent using the [List Notifications API Route](https://docs.medusajs.com/api/admin#notifications_getnotifications). You can pass as a body parameter the \`to\` or \`event_name\` parameters to filter out the notification you just sent. - -2. Send a request to the [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend) using the ID retrieved from the previous request. You can pass the \`to\` parameter in the body to change the receiver of the notification. - -3. You should see the message “Notification Resent” in your console. - `, +`, ], }, } diff --git a/www/vale/styles/docs/ModuleNames.yml b/www/vale/styles/docs/ModuleNames.yml index 27e56d0385..d3683a9325 100644 --- a/www/vale/styles/docs/ModuleNames.yml +++ b/www/vale/styles/docs/ModuleNames.yml @@ -13,4 +13,7 @@ exceptions: - the same module - the other module - the referencing module - - the link module \ No newline at end of file + - the link module + - the first module + - the second module + - the provider module \ No newline at end of file