diff --git a/.github/workflows/generate-preview-references.yml b/.github/workflows/generate-preview-references.yml index 46c78a570ad1d..538241de30038 100644 --- a/.github/workflows/generate-preview-references.yml +++ b/.github/workflows/generate-preview-references.yml @@ -6,5 +6,60 @@ on: jobs: preview-references: uses: ./.github/workflows/generate-resources-reference.yml - preview-api-ui: - uses: ./.github/workflows/generate-public-references.yml \ No newline at end of file + preview-api: + name: Generate OAS + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + with: + access_token: ${{ github.token }} + + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: "yarn" + + - name: Install dependencies + uses: ./.github/actions/cache-deps + with: + extension: reference + + - name: Build Packages + run: yarn build + + - name: Install www/utils Dependencies + run: yarn + working-directory: www/utils + + - name: Build www/utils packages + run: yarn build + working-directory: www/utils + + - name: Run docblock generator + run: "yarn generate:oas" + working-directory: www/utils + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GIT_OWNER: ${{ github.repository_owner }} + GIT_REPO: medusa + + - name: Generate API Reference (v2) + run: yarn openapi:generate + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + commit-message: "chore(docs): Generated API Reference (v2)" + base: "develop" + title: "chore(docs): Updated API Reference (v2)" + labels: "type: chore" + add-paths: www/apps/api-reference/specs + branch: "docs/generate-api-ref" + branch-suffix: "timestamp" \ No newline at end of file diff --git a/.github/workflows/generate-public-references.yml b/.github/workflows/generate-public-references.yml index 1bd37ee54c971..104750c96423d 100644 --- a/.github/workflows/generate-public-references.yml +++ b/.github/workflows/generate-public-references.yml @@ -1,6 +1,5 @@ name: Generate Public References on: - workflow_call: workflow_dispatch: inputs: referenceName: @@ -13,7 +12,7 @@ on: jobs: api-v2: runs-on: ubuntu-latest - if: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event.inputs.referenceName == 'all' || github.event.inputs.referenceName == 'api' }} + if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' || github.event.inputs.referenceName == 'all' || github.event.inputs.referenceName == 'api' }} steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.11.0 @@ -23,7 +22,6 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - token: ${{ secrets.REFERENCE_PAT }} fetch-depth: 0 - name: Setup Node.js environment @@ -63,7 +61,7 @@ jobs: branch-suffix: "timestamp" ui: runs-on: ubuntu-latest - if: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event.inputs.referenceName == 'all' || github.event.inputs.referenceName == 'ui' }} + if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' || github.event.inputs.referenceName == 'all' || github.event.inputs.referenceName == 'ui' }} steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.11.0 @@ -73,7 +71,6 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - token: ${{ secrets.REFERENCE_PAT }} fetch-depth: 0 - name: Setup Node.js environment diff --git a/.github/workflows/generate-resources-reference.yml b/.github/workflows/generate-resources-reference.yml index 29aee1ec9103f..83f40a167e126 100644 --- a/.github/workflows/generate-resources-reference.yml +++ b/.github/workflows/generate-resources-reference.yml @@ -60,12 +60,12 @@ jobs: working-directory: www/utils - name: Generate References - if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} - run: "yarn start generate ${{ github.event.inputs.referenceName }} --merge" + if: ${{ github.event_name == 'workflow_dispatch' }} + run: "yarn start generate ${{ github.event.inputs.referenceName || 'all' }} --merge" working-directory: www/utils/packages/typedoc-generate-references - name: Generate References - if: ${{ github.event_name != 'workflow_dispatch' || github.event_name == 'schedule' }} + if: ${{ github.event_name != 'workflow_dispatch' }} run: "yarn generate:references" working-directory: www/utils diff --git a/www/apps/api-reference/components/Tags/Operation/DescriptionSection/Responses/index.tsx b/www/apps/api-reference/components/Tags/Operation/DescriptionSection/Responses/index.tsx index 57d76bb16a5b7..fcb376a875234 100644 --- a/www/apps/api-reference/components/Tags/Operation/DescriptionSection/Responses/index.tsx +++ b/www/apps/api-reference/components/Tags/Operation/DescriptionSection/Responses/index.tsx @@ -18,11 +18,12 @@ const TagsOperationDescriptionSectionResponses = ({ className={clsx("[&>details:not(:first-of-type)>summary]:border-t-0")} > {Object.entries(responses).map(([code, response], index) => { + const successCode = code.startsWith("20") return ( {response.content && ( <> - {(code === "200" || code === "201") && ( + {successCode && ( <> )} - {code !== "200" && code !== "201" && ( + {!successCode && (
- {code === "200" || code === "201" ? "Success" : "Error"} + + {successCode ? "Success" : "Error"} } expandable={false} diff --git a/www/apps/api-reference/package.json b/www/apps/api-reference/package.json index 129286a085fb4..808bccf6d78e4 100644 --- a/www/apps/api-reference/package.json +++ b/www/apps/api-reference/package.json @@ -59,6 +59,6 @@ "types": "*" }, "engines": { - "node": ">=18.17.0" + "node": ">=20" } } diff --git a/www/apps/book/app/_plugins/create-plugin/page.mdx b/www/apps/book/app/_plugins/create-plugin/page.mdx deleted file mode 100644 index b25df97aabfe6..0000000000000 --- a/www/apps/book/app/_plugins/create-plugin/page.mdx +++ /dev/null @@ -1,85 +0,0 @@ -export const metadata = { - title: `${pageNumber} Create a Plugin`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to create a plugin. - -## Plugin Development Process - -A plugin consists of Medusa application customizations. So, start with a new Medusa application and build your plugin’s resources. - -Once you’re done developing and testing your customizations, you can package them in a plugin to be installed in other Medusa applications. - -![Diagram visualizing the plugin development process.](https://res.cloudinary.com/dza7lstvk/image/upload/v1708506149/Medusa%20Book/plugin-development-process_hls7bh.jpg) - -This chapter explains the steps to create the plugin that packages those customizations. The next chapter explains how to publish the plugin to NPM. - ---- - -## Changes to package.json - -### Add Prepare Script - -Your plugin’s customizations must be built for production use. So, add a new `prepare` script to your scripts in `package.json`: - -```json title="package.json" -"scripts": { - // other scripts... - "prepare": "cross-env NODE_ENV=production npm run build:server && medusa-admin bundle" -} -``` - -This builds your application resources, such as services and API routes, and creates a production build of your admin customizations. If your plugin doesn’t have any admin customizations, remove the `medusa-admin bundle` part of the script. - - - -`cross-env` is already a dependency in your Medusa application. If not, make sure to install it. - - - -### Change Dependencies - -Your Medusa application requires dependencies that are not relevant to a plugin. For example, you can remove other plugins like `@medusajs/file-local` or modules like `@medusajs/cache-inmemory`. - - - -Make sure to remove those plugins/modules from `medusa-config.js`. - - - -In addition, move `@medusajs/medusa` to be a peer dependency: - -```json title="package.json" -"peerDependencies": { - "@medusajs/medusa": "YOUR_MEDUSA_VERSION", - // other peer dependencies... -} -``` - -If your plugin includes admin customizations, add `react` and `react-router-dom` (if you’re using it) to the `peerDependencies` as well: - -```json title="package.json" -"peerDependencies": { - // other dependencies... - "react": "^18.2.0", - "react-router-dom": "^6.13.0" -} -``` - ---- - -## File Changes - -Your Medusa application has files that aren’t relevant to your plugin. For example, files like `src/model/onboarding.ts` used for the onboarding process. - -Go through all files under the `src` directory and remove those that aren’t relevant to your plugin. - ---- - -## Plugin Structure - -A published plugin must have its customizations built into the `dist` directory or to the root of the package. This is handled by the `prepare` command you added earlier. - -Once your plugin is created, you’re ready to publish and use it in Medusa applications. diff --git a/www/apps/book/app/_plugins/integration-services/page.mdx b/www/apps/book/app/_plugins/integration-services/page.mdx deleted file mode 100644 index 31282e822a8b5..0000000000000 --- a/www/apps/book/app/_plugins/integration-services/page.mdx +++ /dev/null @@ -1,102 +0,0 @@ -export const metadata = { - title: `${pageNumber} Integration Services`, -} - -# {metadata.title} - -In this chapter, you’ll learn about special service types used when integrating third-party services. - -## Notification Service - -A notification service is used to send notifications, such as email, in your Medusa application. - -For example, the SendGrid plugin contains a notification service. When the plugin is installed, the Medusa application resolves its notification service to send emails using SendGrid. - -A notification service must extend the `AbstractNotificationService` class from the `@medusajs/medusa` package. - -Refer to [this reference](!resources!/notification-service) to learn more about creating a notification service. - ---- - -## File Service - -A file service is used to upload and download files in your Medusa application. - -For example, the S3 plugin contains a file service. When the plugin is installed, the Medusa application resolves its file service to upload and download files, such as product images. - -A file service must extend the `AbstractFileService` class from the `@medusajs/medusa` package. - -Refer to [this reference](!resources!/file-service) to learn more about creating a file service. - ---- - -## Search Service - -A search service is used to search data in your store, such as products. - -For example, the MeiliSearch plugin contains a search service. When the plugin is installed, the Medusa application resolves its search service when searching for products. - -A search service must extend the `AbstractSearchService` class from the `@medusajs/utils` package. - -Refer to [this reference](!resources!/search-service) to learn more about creating a search service. - ---- - -## Other Integration Types - -If you’re integrating other types of services, such as a CMS or an ERP system, you can create a standard service that extends the `TransactionBaseService` class and implements the necessary methods for your integration. - -Then, you can use that service in other resources, such as an API route or a subscriber. - ---- - -## Integration Services Tips - -### Client Initialization - -Part of the integration is interacting with the third-party service using a client. - -Some third-party services provide a Node.js SDK that you can use. In those cases, you can install the SDK and initialize the client in the constructor. - -In other cases, you can install [axios](https://www.npmjs.com/package/axios) and use it to create a client in the constructor. - -For example: - -```tsx -import { TransactionBaseService } from "@medusajs/medusa" -import { Axios } from "axios" - -type Options = { - erp_url: string - token: string -} - -class ErpService extends TransactionBaseService { - protected client: Axios - - constructor({}, options: Options) { - super(arguments[0], options) - - this.client = new Axios({ - baseURL: options.erp_url, - headers: { - Authorization: `Bearer ${options.token}`, - }, - }) - } - - async retrieveProductErpDetails(productId: string) { - const { data } = await this.client.get( - `/product/${productId}` - ) - - return data - } -} - -export default ErpService -``` - -In the above example, you create a client with `axios`. You use the plugin’s options to set the client’s options, such as the base URL and the authorization token. - -Then, you can use the client in other methods to send requests to the third-party service. \ No newline at end of file diff --git a/www/apps/book/app/_plugins/page.mdx b/www/apps/book/app/_plugins/page.mdx deleted file mode 100644 index e8b99e2a5e26c..0000000000000 --- a/www/apps/book/app/_plugins/page.mdx +++ /dev/null @@ -1,127 +0,0 @@ -import { Table } from "docs-ui" -import { Check, XMark } from "@medusajs/icons" - -export const metadata = { - title: `${pageNumber} Plugin Development`, -} - -# {metadata.title} - -In the next chapters, you’ll learn about plugins, their use in your application, and how to create and publish plugins. - -## What is a Plugin? - -A plugin is an NPM package that consists of Medusa customizations. It adds new functionalities or integrates third-party services, such as a CMS or MeiliSearch. - -Plugins can be added or removed from your Medusa application without causing side effects. - - - -- You're integrating a third-party service into your Medusa application. -- You're creating reusable Medusa application customizations. -- You're providing features that are specific to a Medusa application, such as a migration tool from another platform to Medusa. - - - ---- - -## Plugins vs Modules - -Both plugins and modules are NPM packages that can be installed on your Medusa application without affecting the overall system. - -However, there are key differences between plugins and modules: - - - - - Criteria - Plugins - Modules - - - - - Run in isolation of a Medusa application. - - - - - Can consist of Medusa application customizations, such as API routes or admin widgets. - - - - - Link custom data models to those of Medusa's commerce modules. - - - - - Make architectural changes, such as change the pub/sub service used to emit events. - - - - -
- -## Official and Community Plugins - -Medusa provides official plugins that integrate third-party services like Algolia, SendGrid, S3, and more. - -You can also check out the [Plugins Library](https://medusajs.com/plugins/) for a full list of plugins created by the community. - ---- - -## How are Plugins Installed? - -Plugins are installed through NPM. Then, you must add them to the `plugins` array exported as part of the configurations in `medusa-config.js`. - -If you check the `plugins` array in your `medusa-config.js`, you'll find a few plugins already installed: - -```js title="medusa-config.js" -const plugins = [ - `medusa-fulfillment-manual`, - `medusa-payment-manual`, - { - resolve: `@medusajs/file-local`, - options: { - upload_dir: "uploads", - }, - }, - { - resolve: "@medusajs/admin", - /** @type {import('@medusajs/admin').PluginOptions} */ - options: { - autoRebuild: true, - develop: { - open: false, - }, - }, - }, -] -``` - -The items in the `plugins` array can either be: - -- A string which is the plugin's name. In this case, the plugin doesn't require any options; -- Or an object having the following properties: - - `resolve`: the plugin's name. - - `options`: An object of options to pass to the plugin. - -### Configure Admin Customizations - -If a plugin provides customizations to the admin dashboard, you can pass a special option `enableUI` whose value is a boolean indicating whether the admin customizations should be enabled. By default, its value is `false`. - -For example: - -```js title="medusa-config.js" -const plugins = [ - // ... - { - resolve: `medusa-plugin-custom`, - options: { - // other options... - enableUI: true, - }, - }, -] -``` \ No newline at end of file diff --git a/www/apps/book/app/_plugins/plugin-options/page.mdx b/www/apps/book/app/_plugins/plugin-options/page.mdx deleted file mode 100644 index c3cf97ba2d5e2..0000000000000 --- a/www/apps/book/app/_plugins/plugin-options/page.mdx +++ /dev/null @@ -1,144 +0,0 @@ -import { CodeTabs, CodeTab } from "docs-ui" - -export const metadata = { - title: `${pageNumber} Plugin Options`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to access a plugin’s options in different resources. - -## Services - -In a plugin, a service’s constructor accepts a second parameter: an object holding the plugin’s options. - -For example: - -```ts title="src/services/erp.ts" highlights={[["6", "", "The plugin's options are passed as a parameter."], ["9", "", "Set the plugin's options in a class property."]]} -import { TransactionBaseService } from "@medusajs/medusa" - -class ErpService extends TransactionBaseService { - protected options_: Record - - constructor(container, options) { - super(container, options) - - this.options_ = options - } -} - -export default ErpService -``` - -This adds an `options_` property to the `ErpService` and sets its value using the second parameter of the constructor. You can now use the options in other methods. - ---- - -## API Routes - -To access a plugin’s options in an API route, it’s recommended to expose a getter method in the service for the `options_` property that the API route can use. - -For example: - - - - - ```ts title="src/services/erp.ts" highlights={[["11"], ["12"], ["13"], ["14"], ["15"], ["16"]]} - import { TransactionBaseService } from "@medusajs/medusa" - - class ErpService extends TransactionBaseService { - protected options_: Record - // ... - - get options(): Record { - return this.options_ - } - } - - export default ErpService - ``` - - - - - ```ts title="src/subscribers/customer-created.ts" - import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" - import ErpService from "../../services/erp" - - export async function GET( - req: MedusaRequest, - res: MedusaResponse - ): Promise { - const erpService: ErpService = req.scope.resolve("erpService") - - const pluginOptions = erpService.options - - // use plugin options... - } - ``` - - - - ---- - -## Subscribers - -The object parameter that a subscriber handler function accepts has a `pluginOptions` property. When a subscriber is created in a plugin, this property holds the plugin’s options. - -For example: - -```ts title="src/subscribers/product-updated.ts" highlights={[["7", "", "The plugin's options are passed in the object parameter."]]} -import { - // other imports... - SubscriberArgs, -} from "@medusajs/medusa" - -export default async function productUpdateHandler({ - pluginOptions, -}: SubscriberArgs) { - console.log(`Plugin options: ${pluginOptions}`) -} - -// ... -``` - ---- - -## Scheduled Job - -The object parameter that a scheduled job function accepts has a `pluginOptions` property. When a scheduled job is created in a plugin, this property holds the plugin’s options. - -For example: - -```ts title="src/jobs/once-a-day.ts" highlights={[["6", "", "The plugin's options are passed in the object parameter."]]} -import { - // ... - ScheduledJobArgs, -} from "@medusajs/medusa" - -export default function ({ pluginOptions }: ScheduledJobArgs) { - console.log(`Plugin options: ${pluginOptions}`) -} - -// ... -``` - ---- - -## Loaders - -In a plugin, a loader function accepts a second parameter: an object holding the plugin’s options. - -For example: - -```ts title="src/loaders/on-start.ts" highlights={[["5", "", "The plugin's options are passed as a second parameter to the loader."]]} -import { MedusaContainer } from "@medusajs/medusa" - -export default function ( - container: MedusaContainer, - options: Record -) { - console.log(`Plugin options: ${options}`) -} -``` diff --git a/www/apps/book/app/_plugins/publish-plugin/page.mdx b/www/apps/book/app/_plugins/publish-plugin/page.mdx deleted file mode 100644 index 2fed7b0b7f18c..0000000000000 --- a/www/apps/book/app/_plugins/publish-plugin/page.mdx +++ /dev/null @@ -1,184 +0,0 @@ -import { Table } from "docs-ui" - -export const metadata = { - title: `${pageNumber} Publish a Plugin`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to publish a plugin. After you publish your plugin, it will also be available in [Medusa’s Plugins Library](https://medusajs.com/plugins/). - -## package.json Checklist - -Update the following meta information in your plugin’s package.json: - -- `name`: The name of your plugin. By convention, all plugin names start with `medusa` followed by a descriptive name of what the plugin does. For example, `medusa-payment-stripe`. -- `description`: A short description of what the plugin does. -- `author`: Your name or your company's name. -- `repository`: Details about the repository that holds the source code of the plugin. It's an object that holds the following properties: - - `type`: Should be `git`. - - `url`: The URL to the repository (for example, the GitHub repository holding the code of your plugin). - -### Package Keywords - -It's required for all Medusa plugins to use the keywords `medusa-plugin`. - -The following table mentions other keywords that you can use based on your plugin's functionalities. - - - - - Keyword - Description - - - - - `medusa-plugin-analytics` - Analytics functionalities or integrations. - - - `medusa-plugin-cms` - CMS functionalities or integrations. - - - `medusa-plugin-notification` - Notification functionalities or integrations. - - - `medusa-plugin-payment` - Payment functionalities or integrations. - - - `medusa-plugin-search` - Search functionalities or integrations. - - - `medusa-plugin-shipping` - Shipping functionalities or integrations. - - - `medusa-plugin-storage` - File service or storage integrations. - - - `medusa-plugin-source` - Migrate or import data into Medusa from another platform. - - - `medusa-plugin-admin` - Plugins that include only admin customizations. - - - `medusa-plugin-other` - Any other type of plugin. - - -
- ---- - -## Add NPMIgnore File - -Not all files in your Medusa application are relevant to the published plugin. - -Add the following `.npmignore` file in the root of the plugin's directory to ignore unnecessary files from the published plugin: - -```bash title=".npmignore" -# directories -.cache -.DS_store -.github -.vscode -.yarn -build -data -node_modules -src -uploads - -# files -.babelrc -.env* -.gitignore -.eslintrc -.prettierrc -.yarnrc.yml -index.js -medusa-config.js -yarn.lock -``` - ---- - -## Publish Plugin - - - -To publish a plugin, you need an [NPM account](https://www.npmjs.com/signup). - - - -To publish the plugin: - -1. Run the `prepare` command: - -```bash npm2yarn -npm run prepare -``` - -2. Publish the NPM package: - -```bash -npm publish -``` - -If you haven’t logged in before with NPM, you’ll be asked to log in first. - -Your package is then published to NPM. - ---- - -## Install Plugin in Medusa Applications - -To install your published plugin in a Medusa application, run the following command: - -```bash npm2yarn -npm install medusa-plugin-custom -``` - -Where `medusa-plugin-custom` is your plugin’s name. - -Then, add the plugin to `medusa-config.js`: - -```js title="medusa-config.js" -const plugins = [ - // ... - { - resolve: `medusa-plugin-custom`, - options: { - // plugin options... - }, - }, -] -``` - ---- - -## Update Plugin - -To publish plugin changes, first, run the following command in the plugin’s directory to change the NPM version: - -```bash -npm version -``` - -Where `` indicates the type of version update you’re publishing. For example, `major`. You can see the [full list of types in NPM’s documentation](https://docs.npmjs.com/cli/v8/commands/npm-version). - -Then, publish the new update: - -```bash -npm publish -``` - -You can then update the plugin in the Medusa applications that use it. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_batch-jobs/create/page.mdx b/www/apps/book/app/advanced-development/_batch-jobs/create/page.mdx deleted file mode 100644 index 858a9e3e625d7..0000000000000 --- a/www/apps/book/app/advanced-development/_batch-jobs/create/page.mdx +++ /dev/null @@ -1,82 +0,0 @@ -export const metadata = { - title: `${pageNumber} Create a Batch Job`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to create and process a batch job - - - -The API routes used in this chapter require admin user authentication, and the authentication token is referred to in code snippets as ``. Refer to [this guide](https://docs.medusajs.com/api/admin#authentication) on authenticating admin users. - - - -## 1. Start Medusa Application - -```bash npm2yarn -npm run dev -``` - -## 2. Create a Batch Job - -Use the [Create Batch Job API Route](https://docs.medusajs.com/api/admin#batch-jobs_postbatchjobs) to create a new batch job with the same type as the batch job strategy. - -For example: - -```bash -curl -X POST 'http://localhost:9000/admin/batch-jobs' \ --H 'x-medusa-access-token: ' \ --H 'Content-Type: application/json' \ ---data-raw '{ - "type": "custom", - "context": { } -}' -``` - -In the request body of this API route, you must pass two parameters: - -- `type`: The batch job’s type. You use `custom`, which is the type of batch job strategy created in the previous chapter. -- `context`: An object holding any additional details you want to pass to the batch job. - -This API route creates a batch job in the database. The Medusa application then triggers the processing of the batch job asynchronously. - -## 3. Retrieve Batch Job Status - -To check the current status of the batch job, send a request to the [Get a Batch Job API route](https://docs.medusajs.com/api/admin#batch-jobs_getbatchjobsbatchjob): - -```bash -curl 'http://localhost:9000/admin/batch-jobs/' \ --H 'x-medusa-access-token: ' -``` - -Replace `` with the ID of the batch job returned in the previous step. - -This API route returns the batch job object. Among its properties, the `status` property indicates the status of the batch job. If it started processing, the status is `processing`. If it’s completed, the status is `completed`. - -## 4. Check Console - -Once the batch job’s status is `completed`, check the terminal. You’ll find the following messages: - -```bash -info: Processing batch.created which has 1 subscribers -info: Processing batch.pre_processed which has 0 subscribers -info: Processing batch.confirmed which has 1 subscribers -Processing the batch job! -info: Processing batch.processing which has 0 subscribers -info: Processing batch.completed which has 0 subscribers -``` - -These messages indicate the different stages of the batch job’s lifecycle. Whenever the batch job’s status is changed, an event is triggered to allow batch job strategies to handle them. - -When the batch job’s status is `confirmed`, the batch job is processed, which is why the `Processing the batch job!` message is logged. - -In the next chapter, you’ll learn more about the batch job’s lifecycle. - ---- - -## Alternative Method: BatchJobService - -You can alternatively create and process a batch job using the `BatchJobService`. - -Refer to the `BatchJobService` reference to learn how to use the `create` method. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_batch-jobs/lifecycle/page.mdx b/www/apps/book/app/advanced-development/_batch-jobs/lifecycle/page.mdx deleted file mode 100644 index efb758f837594..0000000000000 --- a/www/apps/book/app/advanced-development/_batch-jobs/lifecycle/page.mdx +++ /dev/null @@ -1,56 +0,0 @@ -export const metadata = { - title: `${pageNumber} Batch Job Lifecycles`, -} - -# {metadata.title} - -In this chapter, you’ll learn about the different lifecycle stages of a batch job based on its status. - -## created - -When a batch job is created through the API route or using the `BatchJobService`, its status is changed to `created` and the `batch.created` event is emitted. - -![A diagram illustrating the created stage](https://res.cloudinary.com/dza7lstvk/image/upload/v1708688547/Medusa%20Book/batch-job-created_gthkwh.jpg) - ---- - -## pre_processed - -Once the `batch.created` event is emitted, the associated batch job strategy is resolved and its `preProcessBatchJob` method is executed. - -Then, the batch job’s status is changed to `pre_processed` and the `batch.pre_processed` event is triggered. - -![A diagram illustrating the pre-processed stage](https://res.cloudinary.com/dza7lstvk/image/upload/v1708524703/Medusa%20Book/batch-job-pre_processed_jx0tvt.jpg) - ---- - -## confirmed - -After the batch job’s status is changed to `pre_processed`, it’s confirmed automatically if the job’s `dry_run` attribute is disabled (which is, by default). The batch job’s status is changed to `confirmed` and the `batch.confirmed` event is triggered. - - - -If you enabled the `dry_run` attribute when you created the batch job, you must confirm it manually either through the [API route](https://docs.medusajs.com/api/admin#batch-jobs_postbatchjobsbatchjobconfirmprocessing) or the `BatchJobService`'s `confirm` method. - - - -![A diagram illustrating the confirmed stage](https://res.cloudinary.com/dza7lstvk/image/upload/v1708525219/Medusa%20Book/batch-job-confirmed_e9pe05.jpg) - ---- - -## processing and completed - -Once the `batch.confirmed` event is emitted, the batch job’s status is changed to `processing` and the `batch.processing` event is emitted. Then, the batch job strategy’s `process` method is executed. - -Once the processing is done, the status of the batch job is changed to `completed` and the `batch.completed` event is emitted. - -![A diagram illustrating the processing and completed stages](https://res.cloudinary.com/dza7lstvk/image/upload/v1708526149/Medusa%20Book/batch-job-processing-completed_svniou.jpg) - ---- - -## Other Lifecycle Stages - -The following lifecycle stages occur only in specific cases: - -- `canceled`: If you cancel a batch job using the [API route](https://docs.medusajs.com/api/admin#batch-jobs_postbatchjobsbatchjobcancel) or `BatchJobService`'s `cancel` method, the batch job’s status is changed to `canceled` and the `batch.canceled` event is emitted. -- `failed`: If an error occurs during any stage, the batch job’s status is changed to `failed` and the `batch.failed` event is emitted. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_batch-jobs/override/page.mdx b/www/apps/book/app/advanced-development/_batch-jobs/override/page.mdx deleted file mode 100644 index a99e7b4a5ac60..0000000000000 --- a/www/apps/book/app/advanced-development/_batch-jobs/override/page.mdx +++ /dev/null @@ -1,46 +0,0 @@ -export const metadata = { - title: `${pageNumber} Override Batch Job Strategies`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to override a batch job strategy. - -## Overview - -Medusa defines batch job strategies for different purposes, such as importing products. - -You can override a strategy from the Medusa application’s core to customize its implementation. For example, you can override the product-import strategy to handle a custom file structure or format. - ---- - -## How to Override a Batch Job Strategy - -To override a batch job strategy, create a new batch job strategy and set its `batchType` property to the same type as the original batch job strategy. - -For example: - -```ts title="src/strategies/custom-product-import.ts" highlights={[["7", "", "Use the same type as the original batch job strategy."]]} -import { - AbstractBatchJobStrategy, - BatchJobService, -} from "@medusajs/medusa" - -class CustomImportProductStrategy - extends AbstractBatchJobStrategy { - static batchType = "product-import" - // ... - } - -export default CustomImportProductStrategy -``` - -This creates a new batch job strategy and sets its type to `product-import`. - -Then, when you create a batch job of the same type, the Medusa application resolves and uses your custom batch job strategy instead of the one defined in Medusa. - - - -Refer to the `AbstractBatchJobStrategy` reference for a full list of methods you can implement. - - \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_batch-jobs/page.mdx b/www/apps/book/app/advanced-development/_batch-jobs/page.mdx deleted file mode 100644 index bfc410b4688bf..0000000000000 --- a/www/apps/book/app/advanced-development/_batch-jobs/page.mdx +++ /dev/null @@ -1,95 +0,0 @@ -export const metadata = { - title: `${pageNumber} Batch Jobs`, -} - -# {metadata.title} - -In this chapter, you’ll learn what batch jobs are and how to create them. - -## What are Batch Jobs and Strategies? - -A batch job is a task performed asynchronously and iteratively in the background of your Medusa application. The task's implementation is defined in a batch job strategy. - -The Medusa application provides API Routes to create a batch job and tracks its progress. You can also create it using the `BatchJobService`'s `create` method. - -When a batch job is created, the associated batch job strategy is used to process it. - ---- - -## How to Create a Batch Job Strategy? - -A batch job strategy is a class created in a TypeScript or JavaScript file under the `src/strategies` directory. The class must extend the `AbstractBatchJobStrategy` class from the `@medusajs/medusa` package. - -For example, create the file `src/strategies/custom.ts` with the following content: - -export const highlights = [ - ["8", "", "A unique identifier associated with the strategy."], - ["9", "", "The type of batch job that this strategy is used for."], - ["11", "processJob", "Defines the task to perform when the batch job is processed."], - ["14", "buildTemplate", "This method is only useful if your batch job provides a template file or text that users can download."] -] - -```ts title="src/strategies/custom.ts" highlights={highlights} -import { - AbstractBatchJobStrategy, - BatchJobService, -} from "@medusajs/medusa" - -class CustomJobStrategy extends AbstractBatchJobStrategy { - protected batchJobService_: BatchJobService - static identifier = "custom-strategy" - static batchType = "custom" - - async processJob(batchJobId: string): Promise { - console.log("Processing the batch job!") - } - async buildTemplate(): Promise { - return "" - } -} - -export default CustomJobStrategy -``` - -This creates a batch job strategy implementing the required properties and methods. - -### Properties - -A batch job strategy must implement the following properties: - -- `identifier`: A unique identifier associated with the strategy. -- `batchType`: The type of batch job that this strategy is used for. A batch job has a type, and, when it's created, the strategy having that type is used to process the job. - -### Methods - -A batch job strategy must implement the following methods: - -- `processJob`: Defines the task to perform when the batch job is processed. -- `buildTemplate`: This method is only useful if your batch job provides a template file or text that users can download. For example, you can return a template CSV file that showcases the accepted CSV format for product import. If your batch job doesn’t support that, you can return an empty string. - -A batch job strategy can also implement methods that run before and after a batch job is processed or when it fails. Refer to the Batch Job Strategy reference for all available methods. - ---- - -## When to Use - - - -- You’re implementing an asynchronous job that’s triggered manually. -- You're tracking the status of the asynchronous job. -- You're keeping track of all batch job executions, which are stored in the database. - - - - - -- You want to trigger the asynchronous job automatically. Instead, use scheduled jobs. You can also create the batch job in a scheduled job. -- You want the task to be performed and finished before consecutive tasks. Instead, use a service. - - - ---- - -## Test Batch Job Strategy - -To test a batch job strategy, use the Admin API Routes to create a batch job of the same type. This is covered in the next chapter. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_services/data-management-tips/page.mdx b/www/apps/book/app/advanced-development/_services/data-management-tips/page.mdx deleted file mode 100644 index ef56cd36ebeaa..0000000000000 --- a/www/apps/book/app/advanced-development/_services/data-management-tips/page.mdx +++ /dev/null @@ -1,216 +0,0 @@ -export const metadata = { - title: `${pageNumber} Data Management Tips`, -} - -# {metadata.title} - -This chapter provides some tips when implementing a service that manages a data model. - -## Filter Records - -Medusa provides a `buildQuery` utility method that accepts filters and returns a query object. Then, the query object can be passed to the Repository’s find and list methods to filter the retrieved methods. - -For example: - -```ts title="src/services/my-custom.ts" highlights={[["8"], ["14"]]} -// other imports -import { - Selector, - buildQuery, -} from "@medusajs/medusa" - -class MyCustomService extends TransactionBaseService { - async list( - selector: Selector - ): Promise { - const myCustomRepo = - this.activeManager_.getRepository(MyCustom) - - const query = buildQuery(selector) - - return await myCustomRepo.find(query) - } -} -``` - -The `buildQuery` method accepts a parameter of type `Selector` provided by Medusa. `Selector` accepts the target data model as a type argument. - -When implementing a `list` method like the above, you can define a selector parameter that can be passed to the method to apply filters on the retrieved records. - -For example, to use this method in another resource: - -```ts -const items = await myCustomService.list({ - name: "John", -}) -``` - ---- - -## Paginate Records - -The `buildQuery` method accepts an optional second parameter of type `FindConfig`, also provided by Medusa. Like `Selector`, it accepts the target data model as a type argument. - -For example, you can change the implementation of the `list` method to the following: - -```ts title="src/services/my-custom.ts" highlights={[["7", "12"]]} -// other imports... -import { FindConfig } from "@medusajs/medusa" - -class MyCustomService extends TransactionBaseService { - async list( - selector: Selector, - config?: FindConfig - ): Promise { - const myCustomRepo = - this.activeManager_.getRepository(MyCustom) - - const query = buildQuery(selector, config) - - return await myCustomRepo.find(query) - } -} -``` - -You add a new parameter to the `list` method of type `FindConfig`, then pass that parameter to `buildQuery`. - -You can now pass pagination fields to the method in another resource: - -```ts -const items = await myCustomService.list( - {}, - { - take: 20, - } -) -``` - -This returns only the first `20` records in the database. - -Other pagination fields include: - -- `skip`: A number indicating how many items to skip before retrieving the records. -- `order`: An object whose keys are names of fields to sort the list by, and value is either `ASC` for ascending sorting or `DESC` for descending sorting. - ---- - -## Select Fields and Relations - -The `FindConfig` type accepts two additional properties: - -- `select`: An array of strings, each being the name of a field in the data model that should be retrieved. When not specified, all fields are retrieved. -- `relations`: An array of strings, each being the name of a relation in the data model that should be retrieved. - -For example: - -```ts -const items = await myCustomService.list( - {}, - { - select: ["name"], - } -) -``` - ---- - -## Management Operations - -The repository provides all necessary operations to manage a data model including creating, updating, and deleting records. For a full list of repository methods, check out [Typeorm’s documentation](https://typeorm.io/repository-api). - ---- - -## Example: CRUD Operations - -Below is an example of a service that implements Create, Read, Update, and Delete (CRUD) operations on a data model. - -
- - ```ts title="src/services/my-custom.ts" - import { - FindConfig, - Selector, - TransactionBaseService, - buildQuery, - } from "@medusajs/medusa" - import { MedusaError } from "@medusajs/utils" - import { MyCustom } from "../models/my-custom" - - class MyCustomService extends TransactionBaseService { - async list( - selector: Selector, - config?: FindConfig - ): Promise { - const myCustomRepo = - this.activeManager_.getRepository(MyCustom) - - const query = buildQuery(selector, config) - - return await myCustomRepo.find(query) - } - async retrieve( - id: string, - config?: FindConfig - ): Promise { - const myCustomRepo = - this.activeManager_.getRepository(MyCustom) - - const query = buildQuery( - { - id, - }, - config - ) - const custom = await myCustomRepo.findOne(query) - - if (!custom) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Record was not found` - ) - } - - return custom - } - - async create(data: Omit): Promise { - return await this.atomicPhase_(async (manager) => { - const myCustomRepo = manager.getRepository(MyCustom) - - const custom = myCustomRepo.create(data) - - return await myCustomRepo.save(custom) - }) - } - - async update( - id: string, - data: Omit - ): Promise { - return await this.atomicPhase_(async (manager) => { - const myCustomRepo = manager.getRepository(MyCustom) - const custom = await this.retrieve(id) - - for (const [key, value] of Object.entries(data)) { - custom[key] = value - } - - return await myCustomRepo.save(custom) - }) - } - - async delete(id: string): Promise { - return await this.atomicPhase_(async (manager) => { - const myCustomRepo = manager.getRepository(MyCustom) - - await myCustomRepo.delete({ - id, - }) - }) - } - } - - export default MyCustomService - ``` - -
\ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_services/data-management/page.mdx b/www/apps/book/app/advanced-development/_services/data-management/page.mdx deleted file mode 100644 index d2c946139b112..0000000000000 --- a/www/apps/book/app/advanced-development/_services/data-management/page.mdx +++ /dev/null @@ -1,111 +0,0 @@ -export const metadata = { - title: `${pageNumber} Data Model Management`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to manage a data model through a service. - -## Entity Manager - -An entity manager allows you to retrieve the repository of a data model, which you can then use to manage records of that model, such as create or update them. - -The `TransactionBaseService` defines an `activeManager_` property, which is an instance of the entity manager. Services can use that property to retrieve a repository. - -For example: - -```ts title="src/services/my-custom.ts" highlights={[["7"]]} -import { TransactionBaseService } from "@medusajs/medusa" -import { MyCustom } from "../models/my-custom" - -class MyCustomService extends TransactionBaseService { - async retrieve(id: string): Promise { - const myCustomRepo = - this.activeManager_.getRepository(MyCustom) - - // use repository... - } -} - -export default MyCustomService -``` - -You use the entity manager’s `getRepository` method to retrieve the repository of a data model. The method accepts the data model as a parameter. - ---- - -## Transaction Entity Managers - -The function parameter of the `atomicPhase_` method accepts an instance of the transaction’s entity manager as a parameter. When retrieving a data model’s repository or performing database operations, you must use the transaction entity manager parameter. - -### Retrieve Repository - -```ts title="src/services/my-custom.ts" highlights={[["5"], ["6"]]} -class MyCustomService extends TransactionBaseService { - // ... - - async create(data: any): Promise { - return await this.atomicPhase_(async (manager) => { - const myCustomRepo = manager.getRepository(MyCustom) - - // use repository... - }) - } -} -``` - -### Custom Services - -If you’re using methods of custom services within the transaction, you must call the `withTransaction` method of the service first and pass the transaction entity manager as a parameter. Then, chain the call with the call to the desired method. - -For example: - -```ts title="src/services/my-custom.ts" highlights={[["8"], ["9"]]} -class MyCustomService extends TransactionBaseService { - // ... - - async create(data: any): Promise { - return await this.atomicPhase_(async (manager) => { - // ... - const customData = await this.myOtherCustomService - .withTransaction(manager) - .retrieve(id) - }) - } -} -``` - -### Commerce Module Services - -All methods of Commerce Module services accept an object as a last parameter that's used to pass shared resources, such as the transaction manager in this case. - -So, when using a Commerce Module service's method in a transaction, pass the transaction manager as part of the last object parameter. - -For example: - -```ts title="src/services/hello-world.ts" highlights={[["17"]]} -class HelloWorldService extends TransactionBaseService { - // ... - async updateProduct( - productId: string, - data: UpdateProductDTO - ): Promise { - return await this.atomicPhase_(async (manager) => { - // example of a database operation - const product = await this.productModuleService.update( - [ - { - ...data, - id: productId, - }, - ], - { - transactionManager: manager, - } - ) - - return product[0] - }) - } -} -``` \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/_services/transactions/page.mdx b/www/apps/book/app/advanced-development/_services/transactions/page.mdx deleted file mode 100644 index 63a9f7ab02e92..0000000000000 --- a/www/apps/book/app/advanced-development/_services/transactions/page.mdx +++ /dev/null @@ -1,71 +0,0 @@ -export const metadata = { - title: `${pageNumber} Transactions in Services`, -} - -# {metadata.title} - -In this chapter, you’ll learn about transactions and how to use them in a service. - -## What is a Transaction? - -A transaction wraps a set of operations to ensure that when an error occurs, all database changes made by the executed operations are rolled back. - -For example, if you have a service with a method that updates data of your custom data model, you can wrap the method’s operations in a transaction. Then, if an error occurs during the method's execution, the data update in the database is rolled back. - ---- - -## How to Use Transactions? - -To use transactions, change your service class to extend the `TransactionBaseService` imported from `@medusajs/medusa`: - -```ts title="src/services/hello-world.ts" highlights={[["8"]]} -import { TransactionBaseService } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" - -type InjectedDependencies = { - productModuleService: IProductModuleService -} - -class HelloWorldService extends TransactionBaseService { - protected productModuleService: IProductModuleService - - constructor({ productModuleService }: InjectedDependencies) { - super(arguments[0]) - - this.productModuleService = productModuleService - } - - // ... -} - -export default HelloWorldService -``` - -Then, use the `TransactionBaseService`'s `atomicPhase_` method that allows you to wrap operations within transactions. - -For example: - -```ts title="src/services/hello-world.ts" highlights={[["11"]]} -// other imports... -import { ProductDTO, UpdateProductDTO } from "@medusajs/types" - -class HelloWorldService extends TransactionBaseService { - // ... - - async updateProduct( - productId: string, - data: UpdateProductDTO - ): Promise { - return await this.atomicPhase_(async (manager) => { - // TODO perform db operation... - }) - } -} -``` - -In the `updateProduct` method, you use the `atomicPhase_` method to wrap the method’s implementation. - -The `atomicPhase_` method accepts a function as a parameter. All database operations performed in the function are wrapped in a transaction. So, if an error occurs in the function, the operations’ database changes are rolled back. - -The data returned by the function parameter is then returned by the `atomicPhase_` method. - \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/admin/tips/page.mdx b/www/apps/book/app/advanced-development/admin/tips/page.mdx index c1f42cafe1928..511fb4f9dd597 100644 --- a/www/apps/book/app/advanced-development/admin/tips/page.mdx +++ b/www/apps/book/app/advanced-development/admin/tips/page.mdx @@ -8,11 +8,7 @@ In this chapter, you'll find some tips for your admin development. ## Routing Functionalities -To navigate or link to other pages, or use other routing functionalities, use the [react-router-dom](https://reactrouter.com/en/main) package: - -```bash npm2yarn -npm install react-router-dom -``` +To navigate or link to other pages, or perform other routing functionalities, use the [react-router-dom](https://reactrouter.com/en/main) package. It's installed in your project through the Medusa Admin. For example: @@ -37,7 +33,7 @@ const ProductWidget = () => { // The widget's configurations export const config = defineWidgetConfig({ - zone: "product.details.after", + zone: "product.details.before", }) export default ProductWidget diff --git a/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx b/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx index a9695c83af258..8288f44d7246f 100644 --- a/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx +++ b/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx @@ -14,15 +14,17 @@ For example, you may add a new page to manage product reviews. --- -## How to Create a UI Route +## How to Create a UI Route? A UI route is created in a file named `page.tsx` under the `src/admin/routes` directory. The file’s default export must be the UI route’s React component. For example, create the file `src/admin/routes/custom/page.tsx` with the following content: ```tsx title="src/admin/routes/custom/page.tsx" +import { Container } from "@medusajs/ui" + const CustomPage = () => { - return
This is my custom route
+ return This is my custom route } export default CustomPage @@ -30,7 +32,9 @@ export default CustomPage The new page’s path is the file’s path relative to `src/admin/routes`. So, the above UI route is a new page added at the path `localhost:9000/app/custom`. -### Test the UI Route +--- + +## Test the UI Route To test the UI route, start the Medusa application: @@ -56,37 +60,6 @@ export const highlights = [ ```tsx title="src/admin/routes/custom/page.tsx" highlights={[["21"], ["22"], ["23"], ["24"], ["25"], ["26"]]} import { defineRouteConfig } from "@medusajs/admin-shared" import { ChatBubbleLeftRight } from "@medusajs/icons" - -const CustomPage = () => { - return
This is my custom route
-} - -export const config = defineRouteConfig({ - label: "Custom Route", - icon: ChatBubbleLeftRight, - }) - -export default CustomPage -``` - -The configuration object is creaetd by the `defineRouteConfig` function imported from `@medusajs/admin-shared`. It accepts the following properties: - -- `label`: the new sidebar item’s label. -- `icon`: an optional React component that acts as an icon in the sidebar. - -The above example adds a new sidebar item with the label `Custom Route` and an icon from the [Medusa UI Icons package](!ui!/icons/overview). - ---- - -## Using UI Components - -Similar to Widgets, it’s highly recommended that you use the [Medusa UI package](https://docs.medusajs.com/ui) to match your page’s design with the rest of the Medusa Admin. - -For example, you can rewrite the above UI route to the following: - -```tsx title="src/admin/routes/custom/page.tsx" -import { defineRouteConfig } from "@medusajs/admin-shared" -import { ChatBubbleLeftRight } from "@medusajs/icons" import { Container } from "@medusajs/ui" const CustomPage = () => { @@ -101,6 +74,13 @@ export const config = defineRouteConfig({ export default CustomPage ``` +The configuration object is created using the `defineRouteConfig` function imported from `@medusajs/admin-shared`. It accepts the following properties: + +- `label`: the sidebar item’s label. +- `icon`: an optional React component used as an icon in the sidebar. + +The above example adds a new sidebar item with the label `Custom Route` and an icon from the [Medusa UI Icons package](!ui!/icons/overview). + --- ## Create Settings Page @@ -134,13 +114,7 @@ This adds a page under the path `/app/settings/custom`. An item is also added to ## Path Parameters -A UI route can accept path parameters if the name of any of the directories in its path is of the format `[param]`. For example, `src/admin/routes/custom/[id]/page.tsx`. - -To retrieve the path parameters, install the `react-router-dom` to use its `useParams` hook: - -```bash npm2yarn -npm install react-router-dom -``` +A UI route can accept path parameters if the name of any of the directories in its path is of the format `[param]`. For example, create the file `src/admin/routes/custom/[id]/page.tsx` with the following content: @@ -157,4 +131,6 @@ const CustomPage = () => { export default CustomPage ``` +You access the passed parameter using `react-router-dom`'s [useParams hook](https://reactrouter.com/en/main/hooks/use-params). + If you run the Medusa application and go to `localhost:9000/app/custom/123`, you'll see `123` printed in the page. diff --git a/www/apps/book/app/advanced-development/admin/widgets/page.mdx b/www/apps/book/app/advanced-development/admin/widgets/page.mdx index b43e76a8a214e..86453692b29cc 100644 --- a/www/apps/book/app/advanced-development/admin/widgets/page.mdx +++ b/www/apps/book/app/advanced-development/admin/widgets/page.mdx @@ -23,25 +23,26 @@ A widget is created in a file under the `src/admin/widgets` directory. The file For example, create the file `src/admin/widgets/product-widget.tsx` with the following content: export const widgetHighlights = [ - ["4", "ProductWidget", "The React component of the product widget."], - ["14", "zone", "The zone to inject the widget to."] + ["5", "ProductWidget", "The React component of the product widget."], + ["15", "zone", "The zone to inject the widget to."] ] ```tsx title="src/admin/widgets/product-widget.tsx" highlights={widgetHighlights} import { defineWidgetConfig } from "@medusajs/admin-shared" +import { Container, Heading } from "@medusajs/ui" // The widget const ProductWidget = () => { return ( -
-

Product Widget

-
+ + Product Widget + ) } // The widget's configurations export const config = defineWidgetConfig({ - zone: "product.details.after", + zone: "product.details.before", }) export default ProductWidget @@ -49,15 +50,15 @@ export default ProductWidget The widget only shows the heading `Product Widget`. -Use the `defineWidgetConfig` function imported from `@medusajs/admin-shared` to create and export the widget's configurations. - -The function accepts as a parameter an object with the following property: +Use the `defineWidgetConfig` function imported from `@medusajs/admin-shared` to create and export the widget's configurations. It accepts as a parameter an object with the following property: - `zone`: A string or an array of strings, each being the name of the zone to inject the widget into. -In the example above, the widget is injected after a product’s details. +In the example above, the widget is injected at the top of a product’s details. -### Test the Widget +--- + +## Test the Widget To test out the widget, start the Medusa application: @@ -65,74 +66,52 @@ To test out the widget, start the Medusa application: npm run dev ``` -Then, open a product’s details page. You’ll find your custom widget at the bottom of the page. +Then, open a product’s details page. You’ll find your custom widget at the top of the page. --- ## Detail Widget Props -Widgets that are injected into a details page (for example, `product.details.after`) receive a `data` prop, which is the main data of the details page (for example, the product object). +Widgets that are injected into a details page (for example, `product.details.before`) receive a `data` prop, which is the main data of the details page (for example, the product object). For example: -```tsx title="src/admin/widgets/product-widget.tsx" highlights={[["8"]]} +export const detailHighlights = [ + ["10", "data", "Receive the data as a prop."], + ["11", "AdminProduct", "Pass the expected type of `data` as a type argument."], + ["15", "data.title"] +] + +```tsx title="src/admin/widgets/product-widget.tsx" highlights={detailHighlights} import { defineWidgetConfig } from "@medusajs/admin-shared" +import { Container, Heading } from "@medusajs/ui" import { DetailWidgetProps, AdminProduct, } from "@medusajs/types" +// The widget const ProductWidget = ({ data, }: DetailWidgetProps) => { - return ( -
-

Product Widget {data.title}

-
- ) -} - -export const config = defineWidgetConfig({ - zone: "product.details.after", -}) - -export default ProductWidget -``` - -Notice that the type of the props is `DetailWidgetProps`, which accepts as a type argument the expected type of the data. - ---- - -## Using UI Components - -It’s highly recommended that you use the [Medusa UI package](https://docs.medusajs.com/ui) to match your widget’s design with the rest of the Medusa Admin. - -For example, you can rewrite the above component to the following: - -```tsx title="src/admin/widgets/product-widget.tsx" -import { defineWidgetConfig } from "@medusajs/admin-shared" -import { Container, Heading } from "@medusajs/ui" - -const ProductWidget = () => { return ( - Product Widget + + Product Widget {data.title} + ) } -export const config: WidgetConfig = defineWidgetConfig({ - zone: "product.details.after", +// The widget's configurations +export const config = defineWidgetConfig({ + zone: "product.details.before", }) export default ProductWidget ``` - - -Admin Widgets also support [Tailwind CSS](https://tailwindcss.com/) out of the box. - - +Notice that the type of the props is `DetailWidgetProps`, which accepts as a type argument the expected type of `data`. --- 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 d4cb4c2076f98..66200a8e0be61 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 @@ -8,7 +8,9 @@ In this chapter, you’ll learn about the CORS middleware and how to configure i ## CORS Overview -Cross-Origin Resource Sharing (CORS) allows only configured origins to access your API Routes. For example, if you allow only origins starting with `http://localhost:7001` to access your Admin API Routes, other origins accessing those routes get a CORS error. +Cross-Origin Resource Sharing (CORS) allows only configured origins to access your API Routes. + +For example, if you allow only origins starting with `http://localhost:7001` to access your Admin API Routes, other origins accessing those routes get a CORS error. ### CORS Configurations @@ -30,6 +32,12 @@ module.exports = defineConfig({ This allows the `http://localhost:7001` origin to access the Admin API Routes, and the `http://localhost:8000` origin to access Store API Routes. + + +Learn more about the CORS configurations in [this resource guide](!resources!/references/medusa-config#http). + + + --- ## CORS in Store and Admin Routes @@ -70,13 +78,16 @@ You can do that in the exported middlewares configurations in `src/api/middlewar For example: -export const highlights = [["18", "parseCorsOrigins", "A utility function that parses the CORS configurations in `medusa-config.js`"]] +export const highlights = [["25", "parseCorsOrigins", "A utility function that parses the CORS configurations in `medusa-config.js`"]] -```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" +```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-10" expandButtonLabel="Show Imports" import { - ConfigModule, MiddlewaresConfig, + MedusaNextFunction, + MedusaRequest, + MedusaResponse, } from "@medusajs/medusa" +import { ConfigModule } from "@medusajs/types" import { parseCorsOrigins } from "@medusajs/utils" import cors from "cors" @@ -85,7 +96,11 @@ export const config: MiddlewaresConfig = { { matcher: "/custom*", middlewares: [ - (req, res, next) => { + ( + req: MedusaRequest, + res: MedusaResponse, + next: MedusaNextFunction + ) => { const configModule: ConfigModule = req.scope.resolve("configModule") diff --git a/www/apps/book/app/advanced-development/api-routes/http-methods/page.mdx b/www/apps/book/app/advanced-development/api-routes/http-methods/page.mdx index 71ef9f0700ab5..184e8d88b6d6e 100644 --- a/www/apps/book/app/advanced-development/api-routes/http-methods/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/http-methods/page.mdx @@ -6,9 +6,9 @@ export const metadata = { In this chapter, you'll learn about how to add new API routes for each HTTP method. -## Handlers of HTTP Methods +## HTTP Method Handler -You can export handler functions for more than one HTTP method in a route file. An API route is created for every HTTP method you export a function for. +An API route is created for every HTTP method you export a handler function for in a route file. Allowed HTTP methods are: `GET`, `POST`, `DELETE`, `PUT`, `PATCH`, `OPTIONS`, and `HEAD`. @@ -41,5 +41,5 @@ export const POST = ( This adds two API Routes: -- A `GET` route at `localhost:9000/store/hello-world`. -- A `POST` route at `localhost:9000/store/hello-world`. \ No newline at end of file +- A `GET` route at `http://localhost:9000/store/hello-world`. +- A `POST` route at `http://localhost:9000/store/hello-world`. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/api-routes/middlewares/page.mdx b/www/apps/book/app/advanced-development/api-routes/middlewares/page.mdx index 1c57d4d11e7e0..e3b4d3213495d 100644 --- a/www/apps/book/app/advanced-development/api-routes/middlewares/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/middlewares/page.mdx @@ -8,7 +8,7 @@ In this chapter, you’ll learn about middlewares and how to create them. ## What is a Middleware? -A middleware is a function executed when a request is sent to an API Route. +A middleware is a function executed when a request is sent to an API Route. It's executed before the route handler function. --- @@ -19,14 +19,23 @@ Middlewares are defined in the special file `src/api/middlewares.ts`. The file m For example: ```ts title="src/api/middlewares.ts" -import { MiddlewaresConfig } from "@medusajs/medusa" +import type { + MedusaNextFunction, + MedusaRequest, + MedusaResponse, + MiddlewaresConfig, +} from "@medusajs/medusa" export const config: MiddlewaresConfig = { routes: [ { matcher: "/store*", middlewares: [ - (req, res, next) => { + ( + req: MedusaRequest, + res: MedusaResponse, + next: MedusaNextFunction + ) => { console.log("Received a request!") next() @@ -37,17 +46,16 @@ export const config: MiddlewaresConfig = { } ``` -The middleware configurations object has the property `routes`. Its value is an array of middleware route objects, where each object is a middleware to apply to a route pattern. +The middleware configurations object has the property `routes`. Its value is an array of middleware route objects, each having the following properties: -In the example above, you define a middleware that logs the message `Received a request!` whenever a request is sent to an API route path starting with `/store`. - - +- `matcher`: a string or regular expression indicating the API route path to apply the middleware on. +- `middlewares`: An array of middleware functions. -The `matcher` property can be a string or a regular expression. +In the example above, you define a middleware that logs the message `Received a request!` whenever a request is sent to an API route path starting with `/store`. - +--- -### Test Middleware +## Test the Middleware To test the middleware: @@ -99,10 +107,15 @@ In addition to the `matcher` configuration, you can restrict which HTTP methods For example: -export const highlights = [["7", "", "Apply the middleware only on `POST` requests"]] +export const highlights = [["12", "method", "Apply the middleware only on `POST` requests"]] -```ts title="src/api/middlewares.ts" highlights={highlights} -import { MiddlewaresConfig } from "@medusajs/medusa" +```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" +import type { + MedusaNextFunction, + MedusaRequest, + MedusaResponse, + MiddlewaresConfig, +} from "@medusajs/medusa" export const config: MiddlewaresConfig = { routes: [ @@ -110,7 +123,11 @@ export const config: MiddlewaresConfig = { matcher: "/store*", method: ["POST", "PUT"], middlewares: [ - (req, res, next) => { + ( + req: MedusaRequest, + res: MedusaResponse, + next: MedusaNextFunction + ) => { console.log("Received a request!") next() diff --git a/www/apps/book/app/advanced-development/api-routes/parameters/page.mdx b/www/apps/book/app/advanced-development/api-routes/parameters/page.mdx index 38f5fa19eead4..a3f8cfa0490ad 100644 --- a/www/apps/book/app/advanced-development/api-routes/parameters/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/parameters/page.mdx @@ -8,7 +8,7 @@ In this chapter, you’ll learn about path, query, and request body parameters. ## Path Parameters -To create an API route that accepts a path parameter, create a directory within the route's path whose name is of the format `[param]`. +To create an API route that accepts a path parameter, create a directory within the route file's path whose name is of the format `[param]`. For example, to create an API Route at the path `/message/{id}`, where `{id}` is a path parameter, create the file `src/api/store/hello-world/[id]/route.ts` with the following content: @@ -16,7 +16,7 @@ export const singlePathHighlights = [ ["11", "req.params.id", "Access the path parameter `id`"] ] -```ts title="src/api/store/hello-world/[id]/route.ts" highlights={singlePathHighlights} +```ts title="src/api/store/hello-world/[id]/route.ts" highlights={singlePathHighlights} apiTesting testApiUrl="http://localhost:9000/store/hello-world/{id}" testApiMethod="GET" testPathParams={{ "id": "1" }} import type { MedusaRequest, MedusaResponse, @@ -45,7 +45,7 @@ export const multiplePathHighlights = [ ["13", "req.params.name", "Access the path parameter `name`"] ] -```ts title="src/api/store/hello-world/[id]/name/[name]/route.ts" highlights={multiplePathHighlights} +```ts title="src/api/store/hello-world/[id]/name/[name]/route.ts" highlights={multiplePathHighlights} apiTesting testApiUrl="http://localhost:9000/store/hello-world/{id}/name/{name}" testApiMethod="GET" testPathParams={{ "id": "1", "name": "John" }} import type { MedusaRequest, MedusaResponse, @@ -77,7 +77,7 @@ export const queryHighlights = [ ["11", "req.query.name", "Access the query parameter `name`"], ] -```ts title="src/api/store/hello-world/route.ts" highlights={queryHighlights} +```ts title="src/api/store/hello-world/route.ts" highlights={queryHighlights} apiTesting testApiUrl="http://localhost:9000/store/hello-world" testApiMethod="GET" testQueryParams={{ "name": "John" }} import type { MedusaRequest, MedusaResponse, 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 09a87bdd04fe2..afb6362670f93 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 @@ -6,10 +6,14 @@ export const metadata = { In this chapter, you’ll learn how to create protected routes. -## Default Protected Routes +## What is a Protected Route? A protected route is a route that requires requests to be user-authenticated before performing the route's functionality. Otherwise, the request fails, and the user is prevented access. +--- + +## Default Protected Routes + Medusa applies an authentication guard on the following routes: - Routes starting with `/admin` require an authenticated admin user. @@ -41,13 +45,13 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => { export const AUTHENTICATE = false ``` -Now, any request sent to the `/store/customers/me/custom` API route is allowed, regardless if the customer is authenticated or not. +Now, any request sent to the `/store/customers/me/custom` API route is allowed, regardless if the customer is authenticated. --- ## Access Logged-In Customer -You can access the logged-in customer’s ID in all API routes starting with `/store` using the `user.customer_id` property of the `MedusaRequest` object. +You can access the logged-in customer’s ID in all API routes starting with `/store` using the `auth_context.actor_id` property of the `MedusaRequest` object. For example: @@ -67,7 +71,7 @@ export const GET = async ( ModuleRegistrationName.CUSTOMER ) - const customer = await customerModuleService.retrieve( + const customer = await customerModuleService.retrieveCustomer( req.auth_context.actor_id ) @@ -75,13 +79,13 @@ export const GET = async ( } ``` -In the route handler, you resolve the Customer Module's main service, then use it to retrieve the logged-in customer, if available. +In this example, you resolve the Customer Module's main service, then use it to retrieve the logged-in customer, if available. --- ## Access Logged-In Admin User -You can access the logged-in admin user’s ID in all API Routes starting with `/admin` using the `user.userId` property of the `MedusaRequest` object. +You can access the logged-in admin user’s ID in all API Routes starting with `/admin` using the `auth_context.actor_id` property of the `MedusaRequest` object. For example: @@ -97,17 +101,19 @@ export const GET = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const userService: IUserModuleService = req.scope.resolve( + const userModuleService: IUserModuleService = req.scope.resolve( ModuleRegistrationName.USER ) - const user = await userService.retrieve(req.auth_context.actor_id) + const user = await userModuleService.retrieveUser( + req.auth_context.actor_id + ) // ... } ``` -In the route handler, you resolve the User Module's main service, and then use it to retrieve the logged-in admin user. +In the route handler, you resolve the User Module's main service, then use it to retrieve the logged-in admin user. --- @@ -151,6 +157,5 @@ The `authenticate` middleware function accepts three parameters: 1. The type of user authenticating. Use `user` for authenticating admin users, and `customer` for authenticating customers. 2. An array of the types of authentication methods allowed. Both `user` and `customer` scopes support `session` and `bearer`. The `admin` scope also supports the `api-key` authentication method. -3. An optional object of options having the following properties: - 1. `allowUnauthenticated`: (default: `false`) A boolean indicating whether authentication is required. For example, you may have an API route where you want to access the logged-in customer if available, but guest customers can still access it too. In that case, enable the `allowUnauthenticated` option. - 2. `allowUnregistered`: (default: `false`) A boolean indicating whether new users can be authenticated. +3. An optional object of configurations accepting the following property: + - `allowUnauthenticated`: (default: `false`) A boolean indicating whether authentication is required. For example, you may have an API route where you want to access the logged-in customer if available, but guest customers can still access it too. 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 index 825336d9b4e3f..402f5817b8833 100644 --- a/www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx +++ b/www/apps/book/app/advanced-development/custom-cli-scripts/page.mdx @@ -8,7 +8,7 @@ In this chapter, you'll learn how create and execute custom scripts from Medusa' ## 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. +A custom CLI script is a function to execute through Medusa's CLI tool. This is useful when creating custom Medusa tooling to run through the CLI. --- @@ -19,7 +19,10 @@ To create a custom CLI script, create a TypeScript or JavaScript file under the 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 { + ExecArgs, + IProductModuleService, +} from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/utils" export default async function myScript({ container }: ExecArgs) { @@ -27,7 +30,8 @@ export default async function myScript({ container }: ExecArgs) { ModuleRegistrationName.PRODUCT ) - const [, count] = await productModuleService.listAndCount() + const [, count] = await productModuleService + .listAndCountProducts() console.log(`You have ${count} product(s)`) } @@ -41,7 +45,7 @@ The function receives as a parameter an object having a `container` property, wh To run the custom CLI script, run the Medusa CLI's `exec` command: -```bash npm2yarn +```bash npx medusa exec ./src/scripts/my-script.ts ``` @@ -63,6 +67,6 @@ export default async function myScript({ args }: ExecArgs) { Then, pass the arguments in the `exec` command after the file path: -```bash npm2yarn +```bash npx medusa exec ./src/scripts/my-script.ts arg1 arg2 ``` diff --git a/www/apps/book/app/advanced-development/data-models/configure-properties/page.mdx b/www/apps/book/app/advanced-development/data-models/configure-properties/page.mdx index 2366780f17663..7739769bd5cde 100644 --- a/www/apps/book/app/advanced-development/data-models/configure-properties/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/configure-properties/page.mdx @@ -4,11 +4,11 @@ export const metadata = { # {metadata.title} -In this chapter, you’ll learn how to configure data model properties, such as setting their default value. +In this chapter, you’ll learn how to configure data model properties. ## Property’s Default Value -Use the `default` method of the `model` utility to specify the default value of a property. +Use the `default` method on a property's definition to specify the default value of a property. For example: @@ -62,7 +62,7 @@ export default MyCustom ## Unique Property -The `unique` method indicates that a property’s value must be unique in the database. +The `unique` method indicates that a property’s value must be unique in the database through a unique index. For example: diff --git a/www/apps/book/app/advanced-development/data-models/index/page.mdx b/www/apps/book/app/advanced-development/data-models/index/page.mdx index 3fc7bf7c3a214..4fb6fc9a4678d 100644 --- a/www/apps/book/app/advanced-development/data-models/index/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/index/page.mdx @@ -8,7 +8,7 @@ In this chapter, you’ll learn how to define indices on a data model. ## Define Index on Property -Define an index on a property using the `model` utility's `index` method. +Use the `index` method on a property's definition to define an index. For example: @@ -38,12 +38,12 @@ In this example, you define an index on the `name` property. ## Define Index on Data Model -A data model has an `indexes` method that defines indices on the data model. +A data model has an `indexes` method that defines indices on its properties. The index can be on multiple columns (composite index). For example: export const dataModelIndexHighlights = [ - ["7", "indexes", "Define indices on the data model."], + ["7", "indexes", "Define indices on the data model's properties."], ["9", "on", "Specify the properties to define the index on."] ] diff --git a/www/apps/book/app/advanced-development/data-models/page.mdx b/www/apps/book/app/advanced-development/data-models/page.mdx new file mode 100644 index 0000000000000..dbd11042c370b --- /dev/null +++ b/www/apps/book/app/advanced-development/data-models/page.mdx @@ -0,0 +1,13 @@ +export const metadata = { + title: `${pageNumber} Data Models`, +} + +# {metadata.title} + +In the next chapters, you'll learn more about creating data models, including property types, relationships, and more. + + + +Data models are in active development and may change. + + \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/data-models/property-types/page.mdx b/www/apps/book/app/advanced-development/data-models/property-types/page.mdx index c4bf73b0358e5..677ac19fba15d 100644 --- a/www/apps/book/app/advanced-development/data-models/property-types/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/property-types/page.mdx @@ -25,8 +25,6 @@ const MyCustom = model.define("my_custom", { export default MyCustom ``` -By default, this property is considered to be the data model’s primary key. - --- ## text @@ -180,7 +178,7 @@ export default MyCustom ## array -The `array` method defines an array or strings property. +The `array` method defines an array of strings property. For example: diff --git a/www/apps/book/app/advanced-development/data-models/relationships/page.mdx b/www/apps/book/app/advanced-development/data-models/relationships/page.mdx index 88277dab865fa..0db3719ce9c34 100644 --- a/www/apps/book/app/advanced-development/data-models/relationships/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/relationships/page.mdx @@ -6,6 +6,12 @@ export const metadata = { In this chapter, you’ll learn how to define relationships between data models in your module. + + +Data model relationships are in active development and may change. + + + ## What is a Relationship Property? A relationship property is defined using relation methods, such as `hasOne` or `belongsTo`. It represents a relationship between two data models in a module. diff --git a/www/apps/book/app/advanced-development/data-models/searchable-property/page.mdx b/www/apps/book/app/advanced-development/data-models/searchable-property/page.mdx index a125b7a810fb2..931ffe00a6ff7 100644 --- a/www/apps/book/app/advanced-development/data-models/searchable-property/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/searchable-property/page.mdx @@ -16,7 +16,7 @@ When the `q` filter is passed, the query is applied on searchable properties in ## Define a Searchable Property -The `searchable` method of the `model` utility indicates that a `text` property is searchable. +Use the `searchable` method on a `text` property to indicate that it's searchable. For example: diff --git a/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx b/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx index ac8be48ab98b6..d54acd1fc5a2a 100644 --- a/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx +++ b/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx @@ -6,7 +6,7 @@ export const metadata = { In this chapter, you'll learn how subscribers receive an event's data payload. -## How to Access Data Payload +## Access Event's Data Payload When events are emitted, they’re emitted with a data payload. @@ -40,6 +40,8 @@ export const config: SubscriberConfig = { This logs the product ID received in the `product.created` event’s data payload to the console. +--- + ## List of Events with Data Payload Refer to [this reference](!resources!/events-reference) for a full list of events emitted by Medusa and their data payloads. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx b/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx deleted file mode 100644 index 18e8162228778..0000000000000 --- a/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx +++ /dev/null @@ -1,87 +0,0 @@ -export const metadata = { - title: `${pageNumber} Loaders Outside Modules`, -} - -# {metadata.title} - -In this chapter, you’ll learn how to create a loader outside a module. - -## Loaders in the Medusa Application - -In your Medusa application, you can create loaders under the `src/loaders` directory outside a module. The Medusa application runs these loaders on start-up. - -This is useful if you’re performing a task on application start-up, but don’t need to define it in a module. - ---- - -## How to Create a Loader Outside a Module? - -To create a loader in your Medusa application outside a module, create a TypeScript or JavaScript file under the `src/loaders` directory that default exports a function. - -For example, create the file `src/loaders/hello-world.ts` with the following content: - -```ts title="src/loaders/hello-world.ts" -export default function () { - console.log("[HELLO LOADER] Just started the Medusa application!") -} -``` - -This loader logs the message `[HELLO LOADER] Just started the Medusa application!` when the Medusa application starts. - -### Test Out the Loader - -To test out your loader, start the Medusa application: - -```bash npm2yarn -npm run dev -``` - -You’ll see in the terminal the logged message, indicating that the loader function was executed successfully. - ---- - -## Resolve Resources - -When the loader function is created outside a module, it receives the Medusa container as a parameter. Use it to resolve other resources in your application, such as a module’s service. - -For example: - -```ts title="src/loaders/hello-world.ts" collapsibleLines="1-5" expandButtonLabel="Show Imports" -import { MedusaContainer } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" - -export default async function (container: MedusaContainer) { - const productModuleService: IProductModuleService = container.resolve( - ModuleRegistrationName.PRODUCT - ) - - const [, count] = await productModuleService.listAndCount() - - console.log(`Hello! You have ${count} product(s)`) -} -``` - -In the loader you resolve the `IProductModuleService`, then use its `listAndCount` method to log in the terminal the number of products in the store. - ---- - -## Medusa Configuration Parameter - -When the loader function is created outside a module, it receives the Medusa configurations defined in `medusa-config.js` as a second parameter. - -For example: - -```ts title="src/loaders/hello-world.ts" -import { MedusaContainer } from "@medusajs/medusa" -import { ConfigModule } from "@medusajs/types" - -export default async function ( - container: MedusaContainer, - config: ConfigModule -) { - console.log(`You have ${Object.values(config.modules || {}).length} modules!`) -} -``` - -This loader logs on application start-up the number of modules defined in your Medusa configurations. 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 e5e21b7ef4b05..7ac09c93353c3 100644 --- a/www/apps/book/app/advanced-development/modules/container/page.mdx +++ b/www/apps/book/app/advanced-development/modules/container/page.mdx @@ -42,12 +42,11 @@ export default class HelloModuleService { // ... } - ``` ### Loader -A loader function in a module accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources. +A loader function accepts as a parameter an object having the property `container`. Its value is the module's container used to resolve resources. For example: @@ -64,5 +63,4 @@ export default function helloWorldLoader({ logger.info("[helloWorldLoader]: Hello, World!") } - ``` diff --git a/www/apps/book/app/advanced-development/modules/isolation/page.mdx b/www/apps/book/app/advanced-development/modules/isolation/page.mdx index aaf2611fdbf82..634b10346b5ab 100644 --- a/www/apps/book/app/advanced-development/modules/isolation/page.mdx +++ b/www/apps/book/app/advanced-development/modules/isolation/page.mdx @@ -4,12 +4,12 @@ export const metadata = { # {metadata.title} -In this chapter, you'll learn about how modules are isolated, and what that means for your custom development. +In this chapter, you'll learn how modules are isolated, and what that means for your custom development. - Modules can't access resources, such as services, from other modules. -- You can use Medusa's tools, explained in the next chapters, to extend modules or implement features across modules. +- You can use Medusa's tools, as explained in the next chapters, to extend a modules' features or implement features across modules. @@ -17,13 +17,13 @@ In this chapter, you'll learn about how modules are isolated, and what that mean A module is unaware of any resources other than its own, such as services or data models. This means it can't access these resources if they're implemented in another module. -For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to another module's data model. +For example, your custom module can't resolve the Product Module's main service or have direct relationships from its data model to the Product Module's data models. --- -## Customize and Implement Features Across Modules +## How to Implement Custom Features Across Modules? -In your Medusa application, you want to implement features that span across modules, or you want to extend existing modules to add new features. +In your Medusa application, you want to implement features that span across modules, or you want to extend an existing module's features and customize them for your own use case. For example, you want to extend the Product Module to add new properties to the `Product` data model. 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 deleted file mode 100644 index 2c53ab8adb49c..0000000000000 --- a/www/apps/book/app/advanced-development/modules/link-modules/page.mdx +++ /dev/null @@ -1,23 +0,0 @@ -export const metadata = { - title: `${pageNumber} Link Modules`, -} - -# {metadata.title} - -In this chapter, you’ll learn what a link module is and how to use the remote link in your customizations. - -## What is a Link Module? - -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 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 create the relationship 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. - - diff --git a/www/apps/book/app/advanced-development/modules/module-links/page.mdx b/www/apps/book/app/advanced-development/modules/module-links/page.mdx new file mode 100644 index 0000000000000..a2dd9d86a114d --- /dev/null +++ b/www/apps/book/app/advanced-development/modules/module-links/page.mdx @@ -0,0 +1,128 @@ +export const metadata = { + title: `${pageNumber} Module Link`, +} + +# {metadata.title} + +In this chapter, you’ll learn what a module link is. + + + +Module links are in active development. + + + +## What is a Module Link? + +A module link forms an association between two data models of different modules, while maintaining module isolation. + +You can then retrieve data across the linked modules, and manage their linked records. + +--- + +## Prerequisite: isQueryable Configuration + +Before you define a module link, you must enable the `isQueryable` configuration of the module. + +For example: + +```js +module.exports = defineConfig({ + // ... + modules: { + helloModuleService: { + resolve: "./modules/hello", + definition: { + isQueryable: true, + }, + }, + }, +}) +``` + +--- + +## How to Define a Module Link? + +### 1. Create Link File + +Links are defined in a TypeScript or JavaScript file under the `src/links` directory. The file defines the link using the `defineLink` function imported from `@medusajs/utils` and exports it. + +For example: + +export const highlights = [ + ["6", "linkable", "Special `linkable` property that holds the linkable data models of `HelloModule`."], + ["7", "linkable", "Special `linkable` property that holds the linkable data models of `ProductModule`."], +] + +```ts title="src/links/hello-product.ts" highlights={highlights} +import HelloModule from "../modules/hello" +import ProductModule from "@medusajs/product" +import { defineLink } from "@medusajs/utils" + +export default defineLink( + HelloModule.linkable.myCustom, + ProductModule.linkable.product +) +``` + +The `defineLink` function accepts as parameters the link configurations of each module's data model. A module has a special `linkable` property that holds these configurations for its data models. + +In this example, you define a module link between the `hello` module's `MyCustom` data model and the Product Module's `Product` data model. + +### 2. Run Migrations + +Medusa stores links as pivot tables in the database, so you must run migrations after defining a link: + +```bash +npx medusa migrations run +``` + +--- + +## Define a List Link + +By default, the defined link establishes a one-to-one relation: a record of a data model is linked to one record of the other data model. + +To specify that a data model can have multiple of its records linked to the other data model's record, use the `isList` option. + +For example: + +```ts +import HelloModule from "../modules/hello" +import ProductModule from "@medusajs/product" +import { defineLink } from "@medusajs/utils" + +export default defineLink( + { + model: HelloModule.linkable.myCustom, + isList: true + }, + ProductModule.linkable.product +) +``` + +In this case, you pass an object of configuration as a parameter rather than the linked model. The object accepts the following properties: + +- `model`: The data model to link. +- `isList`: Whether multiple records can be linked to one record of the other data model. + +In this example, a record of `product` can be linked to more than one record of `myCustom`. + +--- + +## Extend Data Models with Module Links + +Module links are most useful when you want to add properties to a data model of another module. + +For example, to add custom properties to the `Product` data model of the Product Module, you: + +1. Create a module. +2. Create in the module a data model that holds the custom properties you want to add to the `Product` data model. +2. Define a module link that links your module to the Product Module. + +Then, in the next chapters, you'll learn how to: + +- Link each product to a record of your data model. +- Retrieve your data model's properties when you retrieve products. + diff --git a/www/apps/book/app/advanced-development/modules/options/page.mdx b/www/apps/book/app/advanced-development/modules/options/page.mdx index a788b01db3277..cbe7478862606 100644 --- a/www/apps/book/app/advanced-development/modules/options/page.mdx +++ b/www/apps/book/app/advanced-development/modules/options/page.mdx @@ -80,7 +80,7 @@ The object that a module’s loaders receive as a parameter has an `options` pro For example: -```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["16"]]} +```ts title="src/modules/hello/loaders/hello-world.ts" highlights={[["11"], ["12", "ModuleOptions", "The type of expected module options."], ["16"]]} import { LoaderOptions, } from "@medusajs/modules-sdk" 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 index f23af8e0c81e5..e86df78502d88 100644 --- a/www/apps/book/app/advanced-development/modules/remote-link/page.mdx +++ b/www/apps/book/app/advanced-development/modules/remote-link/page.mdx @@ -6,9 +6,15 @@ export const metadata = { In this chapter, you’ll learn what the remote link is and how to use it to manage links. + + +Remote Links are in active development. + + + ## 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. +The remote link is a class with utility methods to manage links between data models. It’s registered in the Medusa container under the `remoteLink` registration name. For example: @@ -38,7 +44,9 @@ export async function POST( You can use its methods to manage links, such as create or delete links. -### Create Link +--- + +## Create Link To create a link between records of two data models, use the `create` method of the remote link. @@ -51,23 +59,25 @@ import { Modules } from "@medusajs/utils" await remoteLink.create({ [Modules.PRODUCT]: { - variant_id: product.variants[0].id, + product_id: "prod_123", }, - [Modules.PRICING]: { - price_set_id: price.id, + "hello": { + my_custom_id: "mc_123", }, }) ``` 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. +The value of each module’s property is an object, whose keys are of the format `{data_model_snake_name}_id`, and values are the IDs of the linked record. -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. +So, in the example above, you link a record of the `MyCustom` data model in a `hello` module to a `Product` record in the Product Module. -### Dismiss Link +--- + +## 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. +To remove a link between records of two data models, use the `dismiss` method of the remote link. For example: @@ -78,19 +88,21 @@ import { Modules } from "@medusajs/utils" await remoteLink.dismiss({ [Modules.PRODUCT]: { - variant_id: product.variants[0].id, + product_id: "prod_123", }, - [Modules.PRICING]: { - price_set_id: price.id, + "hello": { + my_custom_id: "mc_123", }, }) ``` 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. +## Cascade Delete Linked Records + +If a record is deleted, use the `delete` method of the remote link to delete all linked records. For example: @@ -103,16 +115,18 @@ await productModuleService.deleteVariants([variant.id]) await remoteLink.delete({ [Modules.PRODUCT]: { - variant_id: variant.id, + product_id: "prod_123", }, }) ``` -This deletes all records linked to the deleted variant with cascade delete enabled in their relationship. +This deletes all records linked to the deleted product. -### 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. +## Restore Linked Records + +If a record that was previously soft-deleted is now restored, use the `restore` method of the remote link to restore all linked records. For example: @@ -121,77 +135,11 @@ import { Modules } from "@medusajs/utils" // ... -await productModuleService.restoreVariants([variant.id]) +await productModuleService.restoreProducts(["prod_123"]) await remoteLink.restore({ [Modules.PRODUCT]: { - variant_id: variant.id, + product_id: "prod_123", }, }) ``` - ---- - -## 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 96caad6008064..296d163eaea6c 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 @@ -14,27 +14,11 @@ The remote query fetches data across modules. It’s a function registered in th In your resources, such as API routes or workflows, you can resolve the remote query to fetch data across custom modules and Medusa’s commerce modules. ---- - -## isQueryable Configuration + -Before you use remote query on your module, you must enable the `isQueryable` configuration of the module. +- [Enable the isQueryable configuration of the module](../module-links/page.mdx#prerequisite-isqueryable-configuration) -For example: - -```js -module.exports = defineConfig({ - // ... - modules: { - helloModuleService: { - resolve: "./modules/hello", - definition: { - isQueryable: true, - }, - }, - }, -}) -``` + --- @@ -93,6 +77,48 @@ You then pass the query to the `remoteQuery` function to retrieve the results. --- +## Retrieve Linked Records + +Retrieve the records of a linked data model by passing in `fields` the data model's name suffixed with `.*`. + +For example: + +```ts highlights={[["6"]]} +const query = remoteQueryObjectFromString({ + entryPoint: "my_custom", + fields: [ + "id", + "name", + "product.*" + ], +}) +``` + + + +`.*` means that all of data model's properties should be retrieved. To retrieve a specific property, replace the `*` with the property's name. For example, `product.title`. + + + +### Retrieve List Link Records + +If the linked data model has `isList` enabled in the link definition, pass in `fields` the data model's plural name suffixed with `.*`. + +For example: + +```ts highlights={[["6"]]} +const query = remoteQueryObjectFromString({ + entryPoint: "my_custom", + fields: [ + "id", + "name", + "products.*" + ], +}) +``` + +--- + ## Apply Filters ```ts highlights={[["6"], ["7"], ["8"], ["9"]]} @@ -259,6 +285,8 @@ The remote query function alternatively accepts a string with GraphQL syntax as } ` + const result = await remoteQuery(query) + res.json({ my_customs: result, }) 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 5c43265bd6f3a..bd0e2918c4ac0 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 @@ -12,9 +12,9 @@ In this chapter, you’ll learn about what the service factory is and how to use Medusa provides a service factory that your module’s main service can extend. -The service factory generates data management methods for your data models, so you don't have to implement them manually. +The service factory generates data management methods for your data models, so you don't have to implement these methods manually. - + - Your service provides data-management functionalities of your data models. @@ -50,7 +50,7 @@ export default HelloModuleService The `MedusaService` function accepts one parameter, which is an object of data models to generate data-management methods for. -In the example above, the `HelloModuleService` now has methods to manage the `MyCustom` data model, such as `createMyCustoms`. +In the example above, since the `HelloModuleService` extends `MedusaService`, it has methods to manage the `MyCustom` data model, such as `createMyCustoms`. ### Generated Methods diff --git a/www/apps/book/app/advanced-development/page.mdx b/www/apps/book/app/advanced-development/page.mdx index d26956763eddf..5db6c298b4026 100644 --- a/www/apps/book/app/advanced-development/page.mdx +++ b/www/apps/book/app/advanced-development/page.mdx @@ -4,15 +4,12 @@ export const metadata = { # {metadata.title} -In the previous chapters, you got a brief introduction to Medusa’s basic concepts. However, to build a custom commerce application, you need a deeper understanding of how you can utilize these concepts for your business use case. +In the previous chapters, you got a brief introduction to Medusa’s basic concepts. However, to build a custom commerce application, you need a deeper understanding of how you utilize these concepts for your business use case. 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. -- 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. +- Expose API routes with control over authentication. +- Build sophisticated business logic in modules and manage links between them. - Create advanced workflows and configure retries and timeout. - Add new pages to the Medusa Admin. +- Do more with subscribers, scheduled jobs, and other tools. diff --git a/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx b/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx index 21dd64ce6d471..42f2087d612aa 100644 --- a/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx @@ -4,9 +4,9 @@ export const metadata = { # {metadata.title} -In this document, you’ll learn how to access errors that occur during a workflow’s execution. +In this chapter, you’ll learn how to access errors that occur during a workflow’s execution. -## How to Access Workflow Errors +## How to Access Workflow Errors? By default, when an error occurs in a workflow, it throws that error, and the execution stops. diff --git a/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx b/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx index a209c03662e4d..595893ed9bb9c 100644 --- a/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx @@ -23,9 +23,10 @@ Start by creating the file `src/workflows/update-product-erp/index.ts` that will In the file, add the type of the expected workflow input: ```ts title="src/workflows/update-product-erp/index.ts" -import { UpdateProductDTO } from "@medusajs/types" +import { UpsertProductDTO } from "@medusajs/types" + +export type UpdateProductAndErpWorkflowInput = UpsertProductDTO -export type UpdateProductAndErpWorkflowInput = UpdateProductDTO ``` The expected input is the data to update in the product along with the product’s ID. @@ -40,17 +41,9 @@ Create the file `src/workflows/update-product-erp/steps/update-product.ts` with export const updateProductHighlights = [ ["13", "resolve", "Resolve the `ProductService` from the Medusa container."], - [ - "16", - "previousProductData", - "Retrieve the `previousProductData` to pass it to the compensation function.", - ], - ["19", "", "Update the product."], - [ - "39", - "", - "Revert the product’s data using the `previousProductData` passed from the step to the compensation function.", - ], + ["16", "previousProductData", "Retrieve the `previousProductData` to pass it to the compensation function."], + ["19", "updateProducts", "Update the product."], + ["39", "updateProducts", "Revert the product’s data using the `previousProductData` passed from the step to the compensation function."] ] ```ts title="src/workflows/update-product-erp/steps/update-product.ts" highlights={updateProductHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports" @@ -66,9 +59,10 @@ const updateProduct = createStep( context.container.resolve(ModuleRegistrationName.PRODUCT) const { id } = input - const previousProductData = await productModuleService.retrieve(id) + const previousProductData = + await productModuleService.retrieveProduct(id) - const product = await productModuleService.update(id, input) + const product = await productModuleService.updateProducts(id, input) return new StepResponse(product, { // pass to compensation function @@ -82,10 +76,12 @@ const updateProduct = createStep( const { id, type, options, variants, ...previousData } = previousProductData - await productModuleService.update(id, { - ...previousData, - variants: variants.map((variant) => { - const variantOptions = {} + await productModuleService.updateProducts( + id, + { + ...previousData, + variants: variants.map((variant) => { + const variantOptions = {} variant.options.forEach((option) => { variantOptions[option.option.title] = option.value @@ -110,7 +106,7 @@ export default updateProduct In the step: -- You resolve the `ProductService` from the Medusa container. +- You resolve the Product Module's main service from the Medusa container. - You retrieve the `previousProductData` to pass it to the compensation function. - You update and return the product. @@ -211,11 +207,11 @@ Change the content of `src/workflows/update-product-erp/index.ts` to the followi ```ts title="src/workflows/update-product-erp/index.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports" import { createWorkflow } from "@medusajs/workflows-sdk" -import { UpdateProductDTO, ProductDTO } from "@medusajs/types" +import { UpsertProductDTO, ProductDTO } from "@medusajs/types" import updateProduct from "./steps/update-product" import updateErp from "./steps/update-erp" -export type UpdateProductAndErpWorkflowInput = UpdateProductDTO +export type UpdateProductAndErpWorkflowInput = UpsertProductDTO type WorkflowOutput = { product: ProductDTO diff --git a/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx b/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx index e4406c8ac566e..4e80bc3cf1b51 100644 --- a/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx @@ -8,7 +8,7 @@ In this chapter, you'll learn how to add a compensation function to a step. ## Compensation Function -Errors can occur in a workflow. To avoid data inconsistency, define a function to run when an error occurs in a step. This function is called the compensation function. +To avoid data inconsistency when an error is thrown in a workflow, define a function (called a compensation function) and pass it as a second parameter to the `createStep` function. For example: @@ -34,9 +34,11 @@ const step1 = createStep( ) ``` -Each step can have a compensation function. The compensation function only runs if an error occurs throughout the Workflow. It’s useful to undo or roll back actions you’ve performed in a step. +Each step can have a compensation function. The compensation function only runs if an error occurs throughout the workflow. It’s useful to undo or roll back actions you’ve performed in a step. -### Test Compensation Function +--- + +## Test the Compensation Function 1. Add another step that throws an error: @@ -107,7 +109,7 @@ npm run dev 5. Send a `GET` request to `/store/workflow`: -```bash apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/workflows" +```bash apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/workflow" curl http://localhost:9000/store/workflow ``` diff --git a/www/apps/book/app/advanced-development/workflows/constructor-constraints/page.mdx b/www/apps/book/app/advanced-development/workflows/constructor-constraints/page.mdx index ded9b7aa487b5..ced0965b5f2ba 100644 --- a/www/apps/book/app/advanced-development/workflows/constructor-constraints/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/constructor-constraints/page.mdx @@ -4,7 +4,7 @@ export const metadata = { # {metadata.title} -This chapter lists some constraints to keep in mind when defining Workflow constructor functions. +This chapter lists some constraints to keep in mind when defining a workflow's constructor function. ## No Arrow Functions @@ -28,6 +28,8 @@ const myWorkflow = createWorkflow< }) ``` +--- + ## No Async Functions The function passed to the `createWorkflow` can’t be an async function: @@ -50,6 +52,8 @@ const myWorkflow = createWorkflow< }) ``` +--- + ## No Direct Data Manipulation Since the constructor function only defines how the workflow works, you can’t directly manipulate data within the function. Instead, use the `transform` function: diff --git a/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx b/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx index 613f25e61af36..f548a3707698d 100644 --- a/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx @@ -22,11 +22,15 @@ A workflow is considered long-running if at least one step has its `async` confi For example, consider the following workflow and steps: -```ts title="src/workflows/hello-world.ts" highlights={[["13"]]} collapsibleLines="1-10" expandButtonLabel="Show More" -import { createStep, createWorkflow } from "@medusajs/workflows-sdk" +```ts title="src/workflows/hello-world.ts" highlights={[["14"]]} collapsibleLines="1-10" expandButtonLabel="Show More" +import { + createStep, + createWorkflow, + StepResponse, +} from "@medusajs/workflows-sdk" const step1 = createStep("step-1", async () => { - // ... + return new StepResponse({}) }) const step2 = createStep( @@ -35,74 +39,90 @@ const step2 = createStep( async: true, }, async () => { - // ... + return new StepResponse({}) } ) const step3 = createStep("step-3", async () => { - // ... + return new StepResponse("Finished three steps") }) type WorkflowOutput = { message: string } -const myWorkflow = createWorkflow<{}, WorkflowOutput>( - { - name: "hello-world", - }, - function () { - step1() - step2() - step3() +const myWorkflow = createWorkflow< + {}, + WorkflowOutput +>("hello-world", function () { + step1() + step2() + const message = step3() + + return { + message, } -) +}) export default myWorkflow ``` The second step has in its configuration object `async` set to true. This indicates that this step is an asynchronous step. -So, when you execute the `hello-world` workflow, it continues its execution in the background once it reaches the second step. + ---- +An asynchronous step must return for the execution to continue. -## Access Long-Running Workflow Status and Result + - +So, when you execute the `hello-world` workflow, it continues its execution in the background once it reaches the second step. -- [A workflow engine module installed](!resources!/architectural-modules/workflow-engine/in-memory). +--- - +## Access Long-Running Workflow Status and Result To access the status and result of a long-running workflow, use the workflow engine registered in the Medusa Container. The workflow engine provides methods to access and subscribe to workflow executions. For example: export const highlights = [ - ["18", "", "Resolve the workflow engine from the Medusa container."], - ["24", "subscribe", "Subscribe to status changes of the workflow execution."], + ["18", "resolve", "Resolve the workflow engine from the Medusa container."], + ["30", "subscribe", "Subscribe to status changes of the workflow execution."], ] ```ts title="src/api/store/workflows/route.ts" highlights={highlights} collapsibleLines="1-11" expandButtonLabel="Show Imports" import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import myWorkflow from "../../../workflows/hello-world" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" +import { + IWorkflowEngineService, +} from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(req: MedusaRequest, res: MedusaResponse) { const { transaction, result } = await myWorkflow(req.scope).run() - const workflowEngine = req.scope.resolve( + const workflowEngineModuleService = req.scope.resolve< + IWorkflowEngineService + >( ModuleRegistrationName.WORKFLOW_ENGINE ) - await workflowEngine.subscribe({ + const subscriptionOptions = { workflowId: "hello-world", transactionId: transaction.transactionId, - subscriber: (data) => { + subscriberId: "hello-world-subscriber", + } + + await workflowEngineModuleService.subscribe({ + ...subscriptionOptions, + subscriber: async (data) => { if (data.eventType === "onFinish") { console.log("Finished execution", data.result) + // unsubscribe + await workflowEngineModuleService.unsubscribe({ + ...subscriptionOptions, + subscriberOrId: subscriptionOptions.subscriberId, + }) } else if (data.eventType === "onStepFailure") { console.log("Workflow failed", data.step) } @@ -141,3 +161,5 @@ The `subscribe` method accepts an object having three properties: /> Once the workflow execution finishes, the subscriber function is executed with the `eventType` of the received parameter set to `onFinish`. The workflow’s output is set in the `result` property of the parameter. + +You can unsubscribe from the workflow using the workflow engine's `unsubscribe` method, which requires the same object parameter as the `subscribe` method. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx b/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx index ab661c516a4be..d774d442f993f 100644 --- a/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx @@ -8,9 +8,9 @@ In this chapter, you’ll learn how to run workflow steps in parallel. ## parallelize Utility Function -If your workflow has steps that don’t rely on one another’s results, you can run them in parallel. The workflow will wait until all specified steps are finished before continuing with the rest of its implementation. +If your workflow has steps that don’t rely on one another’s results, run them in parallel using the `parallelize` utility function imported from the `@medusajs/workflows-sdk`. -The `parallelize` utility function imported from the `@medusajs/workflows-sdk` package allows you to run the steps in parallel. +The workflow waits until all steps passed to the `parallelize` function finish executing before continuing with the rest of its implementation. For example: @@ -55,4 +55,4 @@ const myWorkflow = createWorkflow< The `parallelize` function accepts the steps to run in parallel as a parameter. -It returns an array of each step’s result. The results are ordered in the result array by the order they're passed in the function's parameter. +It returns an array of the steps' results. The results are ordered based on the `parallelize` parameters' order. \ No newline at end of file diff --git a/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx b/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx index 91d0cbc924f70..00f9c9f05948e 100644 --- a/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx @@ -10,12 +10,13 @@ In this chapter, you’ll learn how to configure steps to allow retrial on failu By default, when an error occurs in a step, the step and the workflow fail, and the execution stops. -You can configure the step to retry on failure. The `createStep` function can accept a configuration object instead of the step’s name as a first parameter: +You can configure the step to retry on failure. The `createStep` function can accept a configuration object instead of the step’s name as a first parameter. -```ts title="src/workflows/hello-world.ts" highlights={[["10"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports" +For example: + +```ts title="src/workflows/hello-world.ts" highlights={[["9"]]} collapsibleLines="1-5" expandButtonLabel="Show Imports" import { createStep, - StepResponse, createWorkflow, } from "@medusajs/workflows-sdk" diff --git a/www/apps/book/app/architectural-concepts/page.mdx b/www/apps/book/app/architectural-concepts/page.mdx deleted file mode 100644 index 0e764159ce6ef..0000000000000 --- a/www/apps/book/app/architectural-concepts/page.mdx +++ /dev/null @@ -1,12 +0,0 @@ -export const metadata = { - title: `${pageNumber} Architectural Concepts`, -} - -# {metadata.title} - -In the next chapters, you’ll learn more about customizable aspects of Medusa’s architecture. - -By the end of these chapters, you’ll learn about: - -- What an architectural module is. -- The different types of architectural modules, including cache and event modules. diff --git a/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx b/www/apps/book/app/architectural-modules/page.mdx similarity index 98% rename from www/apps/book/app/architectural-concepts/architectural-modules/page.mdx rename to www/apps/book/app/architectural-modules/page.mdx index 7039edcaeb0de..19d8fd3cf5c4b 100644 --- a/www/apps/book/app/architectural-concepts/architectural-modules/page.mdx +++ b/www/apps/book/app/architectural-modules/page.mdx @@ -22,7 +22,7 @@ There are different architectural module types including: - 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. +- File Module: Integrates a storage service to handle uploading and managing files. - Notification Module: Integrates a third-party service or defines custom logic to send notifications to users and customers. --- diff --git a/www/apps/book/app/basics/admin-customizations/page.mdx b/www/apps/book/app/basics/admin-customizations/page.mdx index a25a7874bf98a..e1719d93c72a8 100644 --- a/www/apps/book/app/basics/admin-customizations/page.mdx +++ b/www/apps/book/app/basics/admin-customizations/page.mdx @@ -10,9 +10,9 @@ In this chapter, you’ll learn how to customize the Medusa Admin dashboard. The Medusa Admin is an admin dashboard that merchants use to manage their store's data. -You can extend the Medusa Admin to add widgets and new pages. Your customizations interact with API routes to provide merchants with custom functionalities. +You can extend the Medusa Admin to add widgets and new pages. In your customizations, you interact with API routes to provide merchants with custom functionalities. -The Medusa Admin is installed in your Medusa application and runs at the path `/app` when you start the Medusa application. +The Medusa Admin is installed in your Medusa application and runs at `http://localhost:9000/app` when you start the application. --- @@ -34,13 +34,13 @@ const ProductWidget = () => { } export const config = defineWidgetConfig({ - zone: "product.details.after", + zone: "product.details.before", }) export default ProductWidget ``` -This inserts a widget with the text “Product Widget” at the end of a product’s details page. +This inserts a widget with the text “Product Widget” at the beginning of a product’s details page. ### Test the Widget @@ -50,4 +50,4 @@ To test out the widget, start the Medusa application: npm run dev ``` -Then, open a product’s details page. You’ll find your custom widget at the bottom of the page. +Then, open a product’s details page in the Medusa Admin. You’ll find your custom widget at the top of the page. diff --git a/www/apps/book/app/basics/api-routes/page.mdx b/www/apps/book/app/basics/api-routes/page.mdx index 9fe6a85b6de42..0bfc8fd3c4e00 100644 --- a/www/apps/book/app/basics/api-routes/page.mdx +++ b/www/apps/book/app/basics/api-routes/page.mdx @@ -14,11 +14,11 @@ The Medusa core application provides a set of admin and store API routes out-of- --- -## How to Create an API Route +## How to Create an API Route? -An API Route is created in a TypeScript or JavaScript file under the `/src/api` directory of your Medusa application. The file’s name must be `route.ts` or `route.js`. +An API Route is created in a TypeScript or JavaScript file under the `src/api` directory of your Medusa application. The file’s name must be `route.ts` or `route.js`. -Each route file exports API Route handler functions for at least one HTTP method (`GET`, `POST`, `DELETE`, etc…). +Each file exports API Route handler functions for at least one HTTP method (`GET`, `POST`, `DELETE`, etc…). For example, to create a `GET` API Route at `/store/hello-world`, create the file `src/api/store/hello-world/route.ts` with the following content: @@ -58,6 +58,6 @@ curl http://localhost:9000/store/hello-world -- You're exposing custom functionality to be used in the admin dashboard or an external application, such as a storefront. +- You're exposing custom functionality to be used by a storefront, admin dashboard, or any external application. diff --git a/www/apps/book/app/basics/commerce-modules/page.mdx b/www/apps/book/app/basics/commerce-modules/page.mdx index 53e47bb7ac794..b75d2b07fd6de 100644 --- a/www/apps/book/app/basics/commerce-modules/page.mdx +++ b/www/apps/book/app/basics/commerce-modules/page.mdx @@ -18,7 +18,7 @@ Refer to [this reference](!resources!/commerce-modules) for a full list of comme ## Resolve Commerce Module Services -Similarly to your custom module, a commerce module's main service is registered in the Medusa container. So, you can resolve it in your resources, such as API route, to use its functionality. +Similarly to your custom module, a commerce module's main service is registered in the Medusa container. So, you can resolve it in your resources, such as API routes, to use its functionality. For example, you saw this code snippet in the [Medusa container chapter](../medusa-container/page.mdx): diff --git a/www/apps/book/app/basics/data-models/page.mdx b/www/apps/book/app/basics/data-models/page.mdx index 9c4ece4339b26..8993f5b010777 100644 --- a/www/apps/book/app/basics/data-models/page.mdx +++ b/www/apps/book/app/basics/data-models/page.mdx @@ -12,17 +12,17 @@ A data model is a class that represents a table in the database. It's created in --- -## How to Create a Data Model +## How to Create a Data Model? -1. Create data model class in a module. -2. Generate migration for the data model. -4. Run migration to add table for data model in the database. +1. Create a data model in a module. +2. Create migration for the data model. +4. Run migration to add the data model's table in the database. -A data model is created in a TypeScript or JavaScript file under a module's `models` directory. It's defined using the `model` utility imported from `@medjusajs/utils`. +A data model is created in a TypeScript or JavaScript file under a module's `models` directory. It's defined using the `model` utility imported from `@medusajs/utils`. For example, create the file `src/modules/hello/models/my-custom.ts` with the following content: @@ -48,8 +48,6 @@ The example above defines the data model `MyCustom` with the properties `id` and A migration defines changes to be made in the database, such as create or update tables. -So, you must create a migration that creates a table for your data model in the database. - A migration is a class created in a TypeScript or JavaScript file under a module's `migrations` directory. It has two methods: - The `up` method reflects changes on the database. @@ -74,6 +72,15 @@ A migration is a class created in a TypeScript or JavaScript file under a module }) ``` + + + The `databaseName`'s value is only used to generate the migrations. So, make sure it: + + 1. Is unique to the module. Two modules shouldn't have the same database name, and it shouldn't be the same as the Medusa application. + 2. Doesn't change between migrations, as that causes inconsistencies between the migrations. + + + 2. Run the following command in the root directory of your Medusa application: ```bash @@ -95,7 +102,7 @@ For example: ```ts title="src/modules/migrations/Migration20240429090012.ts" import { Migration } from "@mikro-orm/migrations" -export class Migration20240624145652 extends Migration { +export class Migration20240702105919 extends Migration { async up(): Promise { this.addSql("create table if not exists \"my_custom\" (\"id\" text not null, \"name\" text not null, \"created_at\" timestamptz not null default now(), \"updated_at\" timestamptz not null default now(), \"deleted_at\" timestamptz null, constraint \"my_custom_pkey\" primary key (\"id\"));") @@ -120,7 +127,7 @@ The queries performed in each of the methods use PostgreSQL syntax. To reflect the changes in the migration, run the `migration` command: -```bash npm2yarn +```bash npx medusa migrations run ``` diff --git a/www/apps/book/app/basics/events-and-subscribers/page.mdx b/www/apps/book/app/basics/events-and-subscribers/page.mdx index a9c8300ed9680..cdbb0ca209615 100644 --- a/www/apps/book/app/basics/events-and-subscribers/page.mdx +++ b/www/apps/book/app/basics/events-and-subscribers/page.mdx @@ -14,9 +14,11 @@ When an action is performed in Medusa, such as creating a product, the Medusa ap ## What is a Subscriber? -A subscriber is a function executed whenever its associated event is emitted. +A subscriber is a function executed whenever the event it listens to is emitted. -The subscriber is created in a TypeScript or JavaScript file under the `src/subscribers` directory. +### How to Create a Subscriber? + +A subscriber is created in a TypeScript or JavaScript file under the `src/subscribers` directory. For example, create the file `src/subscribers/product-created.ts` with the following content: @@ -36,13 +38,32 @@ export const config: SubscriberConfig = { A subscriber file must export: -- The subscriber function that is an asynchronous function executed whenever the associated event is triggered. +- A subscriber function that is an asynchronous function executed whenever the associated event is triggered. - A configuration object defining the event this subscriber is listening to. The above subscriber listens to the `product.created` event. Whenever the event is emitted, it logs in the terminal `A product is created`. --- +## Test the Subscriber + +To test the subscriber, start the Medusa application: + +```bash npm2yarn +npm run dev +``` + +Then, go to the Medusa Admin at `localhost:9000/app` and create a product. You’ll see the following messages logged in the Medusa application's terminal: + +```bash +info: Processing product.created which has 1 subscribers +A product was created +``` + +The first message indicates that the `product.created` event was emitted, and the second one is the message logged from the subscriber. + +--- + ## When to Use Subscribers @@ -59,16 +80,10 @@ The subscriber function accepts an object parameter with the property `container For example: -{/* TODO change how event names are loaded */} - export const highlights = [ ["10", "container", "Recieve the Medusa Container in the object parameter."], ["13", "resolve", "Resolve the Product Module's main service."], - [ - "13", - "ModuleRegistrationName.PRODUCT", - "The resource registration name imported from `@medusajs/modules-sdk`.", - ], + ["13", "ModuleRegistrationName.PRODUCT", "The module's registration name imported from `@medusajs/modules-sdk`."] ] ```ts title="src/subscribers/product-created.ts" highlights={highlights} @@ -79,12 +94,15 @@ import { ModuleRegistrationName } from "@medusajs/utils" export default async function productCreateHandler({ data, container, -}: SubscriberArgs>) { - const productModuleService: IProductModuleService = container.resolve( - ModuleRegistrationName.PRODUCT - ) +}: SubscriberArgs<{ id: string }>) { + const productModuleService: IProductModuleService = + container.resolve(ModuleRegistrationName.PRODUCT) + + const productId = "data" in data ? data.data.id : data.id - const product = await productModuleService.retrieve(data.id) + const product = await productModuleService.retrieveProduct( + productId + ) console.log(`The product ${product.title} was created`) } diff --git a/www/apps/book/app/basics/loaders/page.mdx b/www/apps/book/app/basics/loaders/page.mdx index 495133242a809..3e1a00491a5cd 100644 --- a/www/apps/book/app/basics/loaders/page.mdx +++ b/www/apps/book/app/basics/loaders/page.mdx @@ -8,9 +8,7 @@ In this chapter, you’ll learn about loaders and how to use them. ## What is a Loader? -A loader is a function executed when the Medusa application starts. - -A module can define loaders to execute on application start-up. +A loader is a function executed when the Medusa application starts. You define and export it in a module. --- @@ -30,25 +28,23 @@ export default function helloWorldLoader() { ### Export Loader in Module Definition -You must export your loaders in the module definition. - -To do that, import the loader in `src/modules/hello/index.ts` and export it in the module's definition: +Import the loader in `src/modules/hello/index.ts` and export it in the module's definition: ```ts title="src/modules/hello/index.ts" // other imports... import helloWorldLoader from "./loaders/hello-world" -// ... - -export default { +export default Module("hello", { // ... loaders: [helloWorldLoader], -} +}) ``` The value of the `loaders` property is an array of loader functions. -### Test Loader +--- + +## Test the Loader Start the Medusa application: @@ -75,6 +71,6 @@ Among the messages logged in the terminal, you’ll see the following message: -- You want to perform an action continuously or at a set time pattern in the application. Use scheduled jobs instead, which is explained in the next chapter. +- You want to perform an action continuously or at a set time pattern in the application. Use scheduled jobs instead, which is explained in an upcoming chapter. diff --git a/www/apps/book/app/basics/medusa-container/page.mdx b/www/apps/book/app/basics/medusa-container/page.mdx index 00fe1ac80bb8d..d28e7a8a01dcc 100644 --- a/www/apps/book/app/basics/medusa-container/page.mdx +++ b/www/apps/book/app/basics/medusa-container/page.mdx @@ -33,7 +33,8 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => { ModuleRegistrationName.PRODUCT ) - const [, count] = await productModuleService.listAndCount() + const [, count] = await productModuleService + .listAndCountProducts() res.json({ count, diff --git a/www/apps/book/app/basics/modules-and-services/page.mdx b/www/apps/book/app/basics/modules-and-services/page.mdx index 4da2c3c4e602a..0aa345f14a952 100644 --- a/www/apps/book/app/basics/modules-and-services/page.mdx +++ b/www/apps/book/app/basics/modules-and-services/page.mdx @@ -14,7 +14,7 @@ Use modules to customize or develop commerce and architectural features in your --- -## How to Create a Module +## How to Create a Module? @@ -28,7 +28,7 @@ Modules are created in a sub-directory of `src/modules`. For example, create the directory `src/modules/hello`. -### 1. Create a Service +### 1. Create Main Service A module must define a service. A service is a TypeScript or JavaScript class holding methods related to a business logic or commerce functionality. @@ -46,21 +46,27 @@ export default class HelloModuleService { A module must have an `index.ts` file in its root directory that exports its definition. The definition specifies the main service of the module. -For example, create the file `src/modules/hello.index.ts` with the following content: +For example, create the file `src/modules/hello/index.ts` with the following content: -```ts title="src/modules/hello.index.ts" highlights={[["4", "", "The main service of the module."]]} +```ts title="src/modules/hello.index.ts" highlights={[["5", "", "The main service of the module."]]} import HelloModuleService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("hello", { service: HelloModuleService, -} +}) ``` +You use the `Module` function imported from `@medusajs/utils` to create the module definition. It requires two parameters: + +1. The module's name. +2. An object with a required property `service` indicating the module's main service. + ### 3. Add Module to Configurations The last step is to add the module in Medusa’s configurations. -In `medusa-config.js`, add the module to the `modules` object: +In `medusa-config.js`, add a `modules` property and pass to it your custom module: ```js title="medusa-config.js" highlights={[["4", "helloModuleService", "The key of the main service to be registered in the Medusa container."]]} module.exports = defineConfig({ @@ -75,23 +81,25 @@ module.exports = defineConfig({ Its key (`helloModuleService`) is the name of the module’s main service. It will be registered in the Medusa container with that name. -Its value is an object having the `resolve` property, whose value is either a path to module's directory (relative to `src`, so it shouldn't include `src` in the path) or an `npm` package’s name. +Its value is an object having the `resolve` property, whose value is either a path to module's directory relative to `src`(it shouldn't include `src` in the path), or an `npm` package’s name. + +--- -### 4. Test the Module +## Test the Module Since the module's main service is registered in the Medusa container, you can resolve it in other resources to use its functionalities. -One way to test the module is to create the API route `src/api/store/custom/route.ts` with the following content: +For example, create the API route `src/api/store/custom/route.ts` with the following content: ```ts title="src/api/store/custom/route.ts" import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import HelloService from "../../../modules/hello/service" +import HelloModuleService from "../../../modules/hello/service" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { - const helloModuleService: HelloService = req.scope.resolve( + const helloModuleService: HelloModuleService = req.scope.resolve( "helloModuleService" ) @@ -128,7 +136,6 @@ You’ll receive the following response: - You're implementing a custom commerce feature. For example, you're implementing digital products. -- You want to extend data models in other commerce modules, such as adding a field or a relation to the `Product` model. - You want to re-use your custom commerce functionalities across Medusa applications or use them in other environments, such as Edge functions and Next.js apps. diff --git a/www/apps/book/app/basics/page.mdx b/www/apps/book/app/basics/page.mdx index a4ae1c7720382..51bedc4967be3 100644 --- a/www/apps/book/app/basics/page.mdx +++ b/www/apps/book/app/basics/page.mdx @@ -4,11 +4,11 @@ export const metadata = { # {metadata.title} -In the next chapters, you’ll learn about the basic concepts of Medusa. These concepts are central to your Medusa development. +In the next chapters, you’ll learn about the basic concepts of Medusa that are central in your development. By the end of these chapter, you’ll be able to: -- Expose your custom functionalities through REST APIs. +- Expose your custom functionalities through endpoints. - Create custom modules that define custom business logic. - Create custom data models. - Execute scripts when the Medusa application starts. diff --git a/www/apps/book/app/basics/important-directories-files/page.mdx b/www/apps/book/app/basics/project-directories-files/page.mdx similarity index 71% rename from www/apps/book/app/basics/important-directories-files/page.mdx rename to www/apps/book/app/basics/project-directories-files/page.mdx index 03490df5e6614..3bde89da89996 100644 --- a/www/apps/book/app/basics/important-directories-files/page.mdx +++ b/www/apps/book/app/basics/project-directories-files/page.mdx @@ -1,10 +1,10 @@ export const metadata = { - title: `${pageNumber} Important Directories and Files`, + title: `${pageNumber} Project Directories and Files`, } # {metadata.title} -In this chapter, you’ll learn about important directories and files in your Medusa application's codebase. +In this chapter, you’ll learn about important directories and files in your Medusa application's project. ## src @@ -13,10 +13,11 @@ This directory is the central place for your custom development. It includes the - `admin`: Holds your admin dashboard's custom components and pages. - `api`: Holds your custom API routes that are added as endpoints in your Medusa application. - `jobs`: Holds your scheduled jobs that run at a specified interval during your Medusa application's runtime. -- `loaders`: Holds your loaders that run at the Medusa application's start-up. - `modules`: Holds your custom modules that implement custom business logic. +- `scripts`: Holds your custom scripts to be executed using Medusa's CLI tool. - `subscribers`: Holds your event listeners that are executed asynchronously whenever an event is emitted. +- `workflows`: Holds your custom flows that can be executed from anywhere in your application. ## medusa-config.js -This file holds your Medusa configurations, such as your PostgreSQL database configurations or your Medusa Admin plugin configurations. +This file holds your Medusa configurations, such as your PostgreSQL database configurations. diff --git a/www/apps/book/app/basics/scheduled-jobs/page.mdx b/www/apps/book/app/basics/scheduled-jobs/page.mdx index b1e492a3cf00c..87849e847a779 100644 --- a/www/apps/book/app/basics/scheduled-jobs/page.mdx +++ b/www/apps/book/app/basics/scheduled-jobs/page.mdx @@ -28,7 +28,7 @@ export default function () { // the job's configurations export const config = { - name: "hello-world", + name: "every-minute-message", // execute every minute schedule: "* * * * *", } @@ -37,10 +37,10 @@ export const config = { A scheduled job file must export: -- The function to be executed whenever it’s time to run the scheduled job. +- A function to be executed whenever it’s time to run the scheduled job. - A configuration object defining the job. It has two properties: - `name`: a unique name for the job. - - `schedule`: a [cron expression](https://crontab.guru/). + - `schedule`: a [cron expression](https://crontab.guru/) specifying when to run the job. This scheduled job executes every minute and logs into the terminal `Time to say hello world!`. @@ -81,13 +81,13 @@ Time to say hello world! ## Resolve Resources -The scheduled job function receives an object parameter that has a `container` property. Its value is the Medusa container, which you can use to resolve resources in your Medusa application, such as services. +The scheduled job function receives a `container` parameter, which is the Medusa container. Use it to resolve resources in your Medusa application, such as services. For example: export const highlights = [ ["11", "resolve", "Resolve the Product Module's main service."], - ["11", "ModuleRegistrationName.PRODUCT", "The resource registration name imported from `@medusajs/modules-sdk`."] + ["11", "ModuleRegistrationName.PRODUCT", "The module's registration name imported from `@medusajs/modules-sdk`."] ] ```ts title="src/jobs/hello-world.ts" highlights={highlights} @@ -111,7 +111,7 @@ export default async function myCustomJob( } export const config = { - name: "hello-world", + name: "every-minute-message", // execute every minute schedule: "* * * * *", } diff --git a/www/apps/book/app/basics/workflows/page.mdx b/www/apps/book/app/basics/workflows/page.mdx index be86a24d905e2..2909d276afbb9 100644 --- a/www/apps/book/app/basics/workflows/page.mdx +++ b/www/apps/book/app/basics/workflows/page.mdx @@ -12,11 +12,11 @@ In this chapter, you’ll learn about workflows and how to define and execute th A workflow is a series of queries and actions that complete a task. -You construct a workflow similar to how you create a JavaScript function, but unlike regular functions, a workflow creates an internal representation of your steps. This makes it possible to keep track of your Workflow’s progress, automatically retry failing steps, and roll back steps. +You construct a workflow similar to how you create a JavaScript function, but unlike regular functions, a workflow creates an internal representation of your steps. This makes it possible to keep track of your workflow’s progress, automatically retry failing steps, and roll back steps. --- -## How to Create and Execute a Workflow +## How to Create and Execute a Workflow? ### 1. Create the Steps @@ -34,7 +34,9 @@ const step1 = createStep("step-1", async () => { This creates one step that returns a hello message. -Steps can accepts input parameters. For example: +Steps can accept input parameters. + +For example, add the following to `src/workflows/hello-world.ts`: ```ts title="src/workflows/hello-world.ts" type WorkflowInput = { @@ -48,7 +50,7 @@ const step2 = createStep("step-2", async ({ name }: WorkflowInput) => { ### 2. Create a Workflow -Next, create the workflow using the `createWorkflow` function: +Next, add the following to the same file to create the workflow using the `createWorkflow` function: ```ts title="src/workflows/hello-world.ts" import { @@ -93,7 +95,7 @@ To execute the workflow, invoke it passing the Medusa container as a parameter. - ```ts title="src/api/store/workflow/route.ts" highlights={[["11"], ["12"], ["13"], ["14"], ["15"], ["16"]]} + ```ts title="src/api/store/workflow/route.ts" highlights={[["11"], ["12"], ["13"], ["14"], ["15"], ["16"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports" import type { MedusaRequest, MedusaResponse, @@ -118,23 +120,30 @@ To execute the workflow, invoke it passing the Medusa container as a parameter. - ```ts title="src/subscribers/customer-created.ts" highlights={[["13"], ["14"], ["15"], ["16"], ["17"], ["18"]]} + ```ts title="src/subscribers/customer-created.ts" highlights={[["20"], ["21"], ["22"], ["23"], ["24"], ["25"]]} collapsibleLines="1-9" expandButtonLabel="Show Imports" import { type SubscriberConfig, type SubscriberArgs, - CustomerService, - Customer, } from "@medusajs/medusa" import myWorkflow from "../workflows/hello-world" + import { ModuleRegistrationName } from "@medusajs/utils" + import { IUserModuleService } from "@medusajs/types" export default async function handleCustomerCreate({ data, container, - }: SubscriberArgs) { + }: SubscriberArgs<{ id: string }>) { + const userId = "data" in data ? data.data.id : data.id + const userModuleService: IUserModuleService = container.resolve( + ModuleRegistrationName.USER + ) + + const user = await userModuleService.retrieveUser(userId) + const { result } = await myWorkflow(container) .run({ input: { - name: data.first_name, + name: user.first_name, }, }) @@ -142,7 +151,7 @@ To execute the workflow, invoke it passing the Medusa container as a parameter. } export const config: SubscriberConfig = { - event: CustomerService.Events.CREATED, + event: "user.created", } ``` @@ -205,7 +214,7 @@ You’ll receive the following response: - You're defining a flow with interactions across multiple systems and services. - You're defining flows to be used across different resources. For example, if you want to invoke the flow manually through an API Router, but also want to automate its running through a scheduled job. -- You want to define how the series of actions are rolled-back when an error occurs. +- You want to define configurations related to errors and how to roll-back steps. This is explained more in later chapters. @@ -240,10 +249,12 @@ type WorkflowOutput = { } const step1 = createStep("step-1", async (_, context) => { - const productModuleService: IProductModuleService = context.container.resolve( - ModuleRegistrationName.PRODUCT - ) - return new StepResponse((await productModuleService.listAndCount())[1]) + const productModuleService: IProductModuleService = + context.container.resolve(ModuleRegistrationName.PRODUCT) + + const [, count] = await productModuleService.listAndCountProducts() + + return new StepResponse(count) }) const myWorkflow = createWorkflow( diff --git a/www/apps/book/app/debugging-and-testing/_feature-flags/page.mdx b/www/apps/book/app/debugging-and-testing/_feature-flags/page.mdx deleted file mode 100644 index a627f3bc96702..0000000000000 --- a/www/apps/book/app/debugging-and-testing/_feature-flags/page.mdx +++ /dev/null @@ -1,88 +0,0 @@ -export const metadata = { - title: `${pageNumber} Feature Flags`, -} - -# {metadata.title} - -In this chapter, you’ll learn about feature flags and how Medusa uses them. - -## What is a Feature Flag? - -A feature flag is a configuration that toggles beta features in Medusa. - -A beta feature may be disabled but is still part of the published `@medusajs/medusa` package. This allows our team to release new features rapidly and continuously without impacting Medusa applications used in production. - -Developers interested in testing a new feature can enable its flag through Medusa’s configurations. - - - -Enabling a feature flag isn’t recommended for Medusa applications in a production environment, as it can cause unexpected errors and issues. - - - -{/* TODO re-add this based on whether we have feature flags (after V2). */} - -{/* --- - -## List of Feature Flags - -Refer to this reference for a full list of feature flags. */} - ---- - -## How to Toggle a Feature Flag - -### Option 1: Using an Environment Variable - -A feature flag has an associated environment variable that, if you set it, it toggles the feature flag. - -For example: - -```bash -MEDUSA_FF_TAX_INCLUSIVE_PRICING=true -``` - -### Option 2: Using Medusa Configurations - -A feature flag also has an associated key that can be used to toggle its value in Medusa’s configurations. - -The configurations exported in `medusa-config.js` has a `featureFlags` property. Its value is an object where each key is the key of a feature flag, and its value is a boolean indicating whether to enable or disable the flag. - -For example: - -```js title="medusa-config.js" -module.exports = defineConfig({ - featureFlags: { - tax_inclusive_pricing: true, - }, - // ... -}) -``` - - - -If you’ve set both the environment variable and the feature flag key in the configurations, the environment variable’s value has a higher precedence. - - - -### Run Migrations - -A feature guarded by a flag may require changes in the database. - -So, after enabling a feature flag, it’s recommended to run migrations in your Medusa application: - -```bash -npx medusa migrations run -``` - -If you disable the feature flag, run the following command to revert migrations: - -```bash -npx medusa migrations revert -``` - - - -This reverts the last migrations, so if you ran other migrations since you toggled the feature flag, it’ll revert them instead. You can run it multiple times to revert the last migrations. - - \ No newline at end of file diff --git a/www/apps/book/app/debugging-and-testing/logging/page.mdx b/www/apps/book/app/debugging-and-testing/logging/page.mdx index 185b1ce5586e8..45204e8f4b380 100644 --- a/www/apps/book/app/debugging-and-testing/logging/page.mdx +++ b/www/apps/book/app/debugging-and-testing/logging/page.mdx @@ -8,7 +8,7 @@ In this chapter, you’ll learn how to use Medusa’s logging utility. ## Logger Class -Medusa provides a `Logger` class that provides advanced logging functionalities. This includes configuring logging levels or saving logs to a file. +Medusa provides a `Logger` class with advanced logging functionalities. This includes configuring logging levels or saving logs to a file. The Medusa application registers the `Logger` class in the Medusa container and each module's container as `logger`. @@ -18,34 +18,43 @@ The Medusa application registers the `Logger` class in the Medusa container and Resolve the `logger` using the Medusa container to log a message in your resource. -For example, create the file `src/loaders/log-message.ts` with the following content: +For example, create the file `src/jobs/log-message.ts` with the following content: export const highlights = [ - ["4", "resolve", "Resolve the `Logger` class."], - ["6", "info", "Log a message of level `info`."] + ["7", "resolve", "Resolve the `Logger` class."], + ["9", "info", "Log a message of level `info`."] ] -```ts title="src/loaders/log-message.ts" highlights={highlights} -import { Logger, MedusaContainer } from "@medusajs/medusa" +```ts title="src/jobs/log-message.ts" highlights={highlights} +import { Logger } from "@medusajs/medusa" +import { MedusaContainer } from "@medusajs/types" -export default async (container: MedusaContainer) => { +export default async function myCustomJob( + container: MedusaContainer +) { const logger: Logger = container.resolve("logger") logger.info("I'm using the logger!") } + +export const config = { + name: "test-logger", + // execute every minute + schedule: "* * * * *", +} ``` -This creates a loader that resolves the `logger` from the Medusa container and uses it to log a message. +This creates a scheduled job that resolves the `logger` from the Medusa container and uses it to log a message. -### Test the Loader +### Test the Scheduled Job -To test out the above loader, start the Medusa application: +To test out the above scheduled job, start the Medusa application: ```bash npm2yarn npm run dev ``` -You’ll see the following message as part of the logged messages: +After a minute, you'll see the following message as part of the logged messages: ```text info: I'm using the logger! @@ -116,7 +125,7 @@ The environment variable must be set as a system environment variable and not in ## Show Log with Progress -The `Logger` class has an `activity` method used to log a message of level `info`. If the Medusa application is running in a development environment, a spinner starts that can be used to show progress and succeed or fail the progress. +The `Logger` class has an `activity` method used to log a message of level `info`. If the Medusa application is running in a development environment, a spinner starts to show the activity's progress. For example: diff --git a/www/apps/book/app/debugging-and-testing/tools/page.mdx b/www/apps/book/app/debugging-and-testing/tools/page.mdx index 02021b4438e16..ac5417041525a 100644 --- a/www/apps/book/app/debugging-and-testing/tools/page.mdx +++ b/www/apps/book/app/debugging-and-testing/tools/page.mdx @@ -16,46 +16,39 @@ Since the Medusa server is a Node.js server, you can use any Node.js testing too [Jest](https://jestjs.io/) is a JavaScript testing framework. Your Medusa project is already configured with Jest; you can use it out-of-the-box. + + +Refer to [Jest's documentation](https://jestjs.io/docs/getting-started) to learn how to install and configure it. + + + For example, consider the following service created at `src/modules/hello/service.ts`: ```ts title="src/modules/hello/service.ts" -import { TransactionBaseService } from "@medusajs/medusa" - -class HelloWorldService extends TransactionBaseService { - constructor(container) { - super(arguments[0]) - } +class HelloModuleService { getMessage(): string { return "Hello, world!" } } -export default HelloWorldService +export default HelloModuleService ``` -You can write a test for it in the file `src/modules/hello/__tests__/hello-world.ts`: +You can write a test for it in the file `src/modules/hello/__tests__/hello-world.spec.ts`: -```ts title="src/modules/hello/__tests__/hello-world.ts" -import HelloWorldService from "../hello-world" +```ts title="src/modules/hello/__tests__/hello-world.spec.ts" +import HelloModuleService from "../service" -describe("HelloWorldService", () => { - const helloWorldService = new HelloWorldService() +describe("HelloModuleService", () => { + const helloModuleService = new HelloModuleService() it("should return hello world message", () => { - expect(helloWorldService.getMessage()).toBe("Hello, world!") + expect(helloModuleService.getMessage()).toBe("Hello, world!") }) }) ``` -Then, run the following command in the root of your Medusa project to run the test: - -```bash npm2yarn -npm run test -``` - -This command looks for TypeScript and JavaScript files under any directory named `__tests__` and runs them. - --- ## IDE Debugging Tools diff --git a/www/apps/book/app/deployment/page.mdx b/www/apps/book/app/deployment/page.mdx index 87ba7c84a6cb6..32d61fc180b04 100644 --- a/www/apps/book/app/deployment/page.mdx +++ b/www/apps/book/app/deployment/page.mdx @@ -25,7 +25,7 @@ You must deploy the Medusa server before the admin or storefront, as both of the ![Diagram showcasing how the Medusa server and its associated services would be deployed](https://res.cloudinary.com/dza7lstvk/image/upload/v1708600972/Medusa%20Book/backend_deployment_pgexo3.jpg) -Since the Medusa server is a Node.js server, it must be deployed to a hosting provider that supports deploying servers, such as Railway, DigitalOcean, AWS, Heruko, etc… +The Medusa server must be deployed to a hosting provider supporting Node.js server deployments, such as Railway, DigitalOcean, AWS, Heruko, etc… @@ -33,7 +33,7 @@ For optimal experience, make sure that the hosting provider and plan offer at le -Your server connects to PostgreSQL and Redis databases. Most hosting providers support deploying and managing these databases along with your Medusa server (such as Railway and DigitalOcean). You can also choose a separate hosting for either of them and connect to them with Medusa’s configurations. +Your server connects to a PostgreSQL database and, optionally, Redis or other services. Most hosting providers support deploying and managing these databases along with your Medusa server (such as Railway and DigitalOcean). Refer to [this reference](!resources!/deployment) to find how-to deployment guides for specific hosting providers. @@ -41,15 +41,9 @@ Refer to [this reference](!resources!/deployment) to find how-to deployment guid ## Deploying the Medusa Admin - - -Admin deployment details are still in the work. - - - ### Deploy Admin with the Server -Since the Medusa Admin is a plugin installed in the server, you may choose to host them together. +The Medusa Admin can be deployed on the same hosting with the server. In this scenario, make sure the hosting provider and plan of your choice provide at least 2GB of RAM, as the admin build requires high RAM usage. @@ -61,17 +55,6 @@ The server deployment guides mention details on how to deploy the admin along wi -### Deploy Admin through GitHub Action - -If you host your server's code on GitHub, you can: - -1. Disable the `autoRebuild` option of the admin plugin. -2. Create a GitHub action that builds the admin before the deployment is triggered. - -With this solution, you can deploy the admin with the server but the hosting provider doesn’t handle the admin building, decreasing the RAM usage. - -![Diagram showcasing how the admin can be built through a GitHub action before deployment](https://res.cloudinary.com/dza7lstvk/image/upload/v1708601239/Medusa%20Book/admin_deployment_1_-_actions_cxjv6h.jpg) - ### Deploy Admin Separately You can deploy the admin into a separate hosting provider or instance. The admin can be hosted on providers that support front-end websites and frameworks, such as Vercel. diff --git a/www/apps/book/app/more-resources/page.mdx b/www/apps/book/app/more-resources/page.mdx index f5beefc3568fd..0ee6c2be227aa 100644 --- a/www/apps/book/app/more-resources/page.mdx +++ b/www/apps/book/app/more-resources/page.mdx @@ -4,10 +4,6 @@ export const metadata = { # {metadata.title} -In this chapter, you’ll find more resources to aid you during your development with Medusa. +The Learning Resources documentation provides guides and references that are useful for your development. This documentation included links to parts of the Learning Resources documentation where necessary. -## Medusa Resources Documentation - -The Medusa Resources documentation provides guides and references that are useful for your development. This book included links to parts of the Medusa Resources documentation where necessary. - -Check out the Medusa Resources documentation [here](!resources!). \ No newline at end of file +Check out the Learning Resources documentation [here](!resources!). \ No newline at end of file diff --git a/www/apps/book/app/page.mdx b/www/apps/book/app/page.mdx index 3bcf73ee943d9..8cec0b4481e23 100644 --- a/www/apps/book/app/page.mdx +++ b/www/apps/book/app/page.mdx @@ -12,7 +12,7 @@ Medusa is a digital commerce platform with a built-in framework for customizatio Medusa's framework includes two types of tools: 1. Modules that provide commerce functionalities, such as Product, Order, and Cart modules. -2. Customization tools to build your business features, such as custom data models, business logic, flows, and API endpoints. +2. Customization tools to build your business features, such as custom data models, business logic, flows, and endpoints. With these tools, you save time you would spend with other platforms on maintaining and setting up your customizations. Instead, you rapidly build important features for your business. @@ -23,7 +23,7 @@ With these tools, you save time you would spend with other platforms on maintain -- [Node.js v16+](https://nodejs.org/en/download) +- [Node.js v20+](https://nodejs.org/en/download) - [Git CLI tool](https://git-scm.com/downloads) - [PostgreSQL](https://www.postgresql.org/download/) @@ -32,7 +32,7 @@ With these tools, you save time you would spend with other platforms on maintain Create your first Medusa store by running the following command: ```bash -npx create-medusa-app@latest --v2 +npx create-medusa-app@preview ``` --- @@ -96,4 +96,4 @@ Medusa is for ambitious businesses and developers that are limited by traditiona This book is for TypeScript or JavaScript developers looking to master Medusa and build their commerce applications. By following this book, you’ll learn about Medusa’s concept, from basic to advanced, with easy-to-follow examples to assist you along the way. -By the end of this book, you’ll be an expert Medusa developer, leading teams using Medusa from the beginning till deployment. \ No newline at end of file +By the end of this book, you’ll be an expert Medusa developer, leading teams using Medusa from the development till production. \ No newline at end of file diff --git a/www/apps/book/app/storefront-development/nextjs-starter/page.mdx b/www/apps/book/app/storefront-development/nextjs-starter/page.mdx index 00677e2ce74e1..0d3a1bc3f5bf5 100644 --- a/www/apps/book/app/storefront-development/nextjs-starter/page.mdx +++ b/www/apps/book/app/storefront-development/nextjs-starter/page.mdx @@ -8,7 +8,7 @@ In this chapter, you’ll learn how to install and use the Next.js Starter store -The Next.js starter is currently in development to fully support Medusa v2. +The Next.js Starter is currently in development to fully support Medusa v2. @@ -21,10 +21,10 @@ The Next.js starter is currently in development to fully support Medusa v2. -1. Clone the `feat/v2` branch of the [Next.js Starter](https://github.com/medusajs/nextjs-starter-medusa): +1. Clone the `v2` branch of the [Next.js Starter](https://github.com/medusajs/nextjs-starter-medusa/tree/v2): ```bash -git clone https://github.com/medusajs/nextjs-starter-medusa -b feat/v2 my-medusa-storefront +git clone https://github.com/medusajs/nextjs-starter-medusa -b v2 my-medusa-storefront ``` 2. Change to the `my-medusa-storefront` directory, install the dependencies, and rename the template environment variable: @@ -61,8 +61,8 @@ You can learn more about development with Next.js through [their documentation]( --- -## Configurations and Compatible Plugins +## Configurations and Integrations -The Next.js Starter is compatible with some Medusa plugins out-of-the-box, such as the MeiliSearch or Stripe plugins. You can also change some of its configurations if necessary. +The Next.js Starter is compatible with some Medusa integrations out-of-the-box, such as the Stripe provider module. You can also change some of its configurations if necessary. -Refer to the Next.js Starter reference for more details. \ No newline at end of file +Refer to the [Next.js Starter reference](!resources!/nextjs-starter) for more details. \ No newline at end of file diff --git a/www/apps/book/app/storefront-development/page.mdx b/www/apps/book/app/storefront-development/page.mdx index 1b3f8f71d23be..4dbf5ab50b04d 100644 --- a/www/apps/book/app/storefront-development/page.mdx +++ b/www/apps/book/app/storefront-development/page.mdx @@ -4,13 +4,9 @@ export const metadata = { # {metadata.title} -In the next chapters, you’ll learn about building a storefront for your Medusa backend. - -## Storefronts in Medusa’s Architecture - Storefronts are built separately from the Medusa application. They interact with the Medusa application through the Store API routes. -You're free to choose how to build your storefront. You can start with our Next.js starter storefront or build a storefront from scratch using your preferred framework or tech stack. +You're free to choose how to build your storefront. You can start with our Next.js starter storefront, as explained in the next chapter, or build a storefront from scratch using your preferred framework or tech stack. diff --git a/www/apps/book/package.json b/www/apps/book/package.json index 79c9a791cccdd..590a13820b9e8 100644 --- a/www/apps/book/package.json +++ b/www/apps/book/package.json @@ -42,6 +42,6 @@ "typescript": "^5" }, "engines": { - "node": ">=18.17.0" + "node": ">=20" } } diff --git a/www/apps/book/sidebar.mjs b/www/apps/book/sidebar.mjs index 3c2220c64be86..de3353ff0ce4c 100644 --- a/www/apps/book/sidebar.mjs +++ b/www/apps/book/sidebar.mjs @@ -17,8 +17,8 @@ export const sidebar = sidebarAttachHrefCommonOptions( title: "The Basics", children: [ { - path: "/basics/important-directories-files", - title: "Important Directories and Files", + path: "/basics/project-directories-files", + title: "Project Directories and Files", }, { path: "/basics/medusa-container", @@ -85,14 +85,14 @@ export const sidebar = sidebarAttachHrefCommonOptions( path: "/advanced-development/api-routes/middlewares", title: "Middlewares", }, - { - path: "/advanced-development/api-routes/cors", - title: "Handling CORS", - }, { path: "/advanced-development/api-routes/protected-routes", title: "Protected Routes", }, + { + path: "/advanced-development/api-routes/cors", + title: "Handling CORS", + }, ], }, { @@ -111,17 +111,17 @@ export const sidebar = sidebarAttachHrefCommonOptions( title: "Module Isolation", }, { - path: "/advanced-development/modules/remote-query", - title: "Remote Query", - }, - { - path: "/advanced-development/modules/link-modules", - title: "Link Modules", + path: "/advanced-development/modules/module-links", + title: "Module Links", }, { path: "/advanced-development/modules/remote-link", title: "Remote Link", }, + { + path: "/advanced-development/modules/remote-query", + title: "Remote Query", + }, { path: "/advanced-development/modules/options", title: "Module Options", @@ -129,6 +129,7 @@ export const sidebar = sidebarAttachHrefCommonOptions( ], }, { + path: "/advanced-development/data-models", title: "Data Models", children: [ { @@ -161,15 +162,6 @@ export const sidebar = sidebarAttachHrefCommonOptions( }, ], }, - { - title: "Loaders", - children: [ - { - path: "/advanced-development/loaders/outside-modules", - title: "Create Outside Module", - }, - ], - }, { title: "Events and Subscribers", children: [ @@ -260,7 +252,7 @@ export const sidebar = sidebarAttachHrefCommonOptions( ], }, { - path: "/architectural-concepts/architectural-modules", + path: "/architectural-modules", title: "Architectural Modules", }, { @@ -275,10 +267,6 @@ export const sidebar = sidebarAttachHrefCommonOptions( path: "/debugging-and-testing/tools", title: "Tools", }, - { - path: "/debugging-and-testing/feature-flags", - title: "Feature Flags", - }, ], }, { diff --git a/www/apps/resources/app/architectural-modules/cache/create/page.mdx b/www/apps/resources/app/architectural-modules/cache/create/page.mdx index e67ad9984cbdc..8b80483d88d34 100644 --- a/www/apps/resources/app/architectural-modules/cache/create/page.mdx +++ b/www/apps/resources/app/architectural-modules/cache/create/page.mdx @@ -135,10 +135,11 @@ Create the file `src/modules/my-cache/index.ts` with the following content: ```ts title="src/modules/my-cache/index.ts" import MyCacheService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-cache", { service: MyCacheService, -} +}) ``` This exports the module's definition, indicating that the `MyCacheService` is the main service of the module. @@ -152,7 +153,7 @@ To use your Cache Module, add it to the `modules` object exported as part of the For example: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/cache/in-memory/page.mdx b/www/apps/resources/app/architectural-modules/cache/in-memory/page.mdx index 98088da2e0d98..6ce0277e36de8 100644 --- a/www/apps/resources/app/architectural-modules/cache/in-memory/page.mdx +++ b/www/apps/resources/app/architectural-modules/cache/in-memory/page.mdx @@ -31,7 +31,7 @@ npm install @medusajs/cache-inmemory Next, add the module into the `modules` property of the exported object in `medusa-config.js`: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/cache/redis/page.mdx b/www/apps/resources/app/architectural-modules/cache/redis/page.mdx index 2d13bb41d55e1..ad5bd76caacd1 100644 --- a/www/apps/resources/app/architectural-modules/cache/redis/page.mdx +++ b/www/apps/resources/app/architectural-modules/cache/redis/page.mdx @@ -31,7 +31,7 @@ export const highlights = [ ] ```js title="medusa-config.js" highlights={highlights} -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/event/create/page.mdx b/www/apps/resources/app/architectural-modules/event/create/page.mdx index 35e3aafe0f9b7..64e5f5d77e74b 100644 --- a/www/apps/resources/app/architectural-modules/event/create/page.mdx +++ b/www/apps/resources/app/architectural-modules/event/create/page.mdx @@ -88,12 +88,13 @@ class MyEventService extends AbstractEventBusModuleService { Create the file `src/modules/my-event/index.ts` with the following content: -```ts +```ts title="src/modules/my-event/index.ts" import MyEventService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-event", { service: MyEventService, -} +}) ``` This exports the module's definition, indicating that the `MyEventService` is the main service of the module. @@ -107,7 +108,7 @@ To use your Event Module, add it to the `modules` object exported as part of the For example: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/event/local/page.mdx b/www/apps/resources/app/architectural-modules/event/local/page.mdx index 93a45f5ed5eea..3bfea54cfe768 100644 --- a/www/apps/resources/app/architectural-modules/event/local/page.mdx +++ b/www/apps/resources/app/architectural-modules/event/local/page.mdx @@ -29,7 +29,7 @@ npm install @medusajs/event-local Next, add the module into the `modules` property of the exported object in `medusa-config.js`: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/event/redis/page.mdx b/www/apps/resources/app/architectural-modules/event/redis/page.mdx index c7912cf935f7b..8d9b1af07c207 100644 --- a/www/apps/resources/app/architectural-modules/event/redis/page.mdx +++ b/www/apps/resources/app/architectural-modules/event/redis/page.mdx @@ -35,7 +35,7 @@ export const highlights = [ ] ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/file/local/page.mdx b/www/apps/resources/app/architectural-modules/file/local/page.mdx index 957a1f67a471c..c64ae741497c5 100644 --- a/www/apps/resources/app/architectural-modules/file/local/page.mdx +++ b/www/apps/resources/app/architectural-modules/file/local/page.mdx @@ -33,7 +33,7 @@ The File Module accepts one provider only. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -46,12 +46,9 @@ module.exports = { providers: [ { resolve: "@medusajs/file-local-next", + id: "local", options: { - config: { - local: { - // provider options... - }, - }, + // provider options... }, }, ], diff --git a/www/apps/resources/app/architectural-modules/file/s3/page.mdx b/www/apps/resources/app/architectural-modules/file/s3/page.mdx index 37131b5d8cdb3..90814616f504d 100644 --- a/www/apps/resources/app/architectural-modules/file/s3/page.mdx +++ b/www/apps/resources/app/architectural-modules/file/s3/page.mdx @@ -85,7 +85,7 @@ The File Module accepts one provider only. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -99,18 +99,15 @@ module.exports = { providers: [ { resolve: "@medusajs/file-s3", + id: "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... - }, - }, + 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... }, }, ], diff --git a/www/apps/resources/app/architectural-modules/notification/local/page.mdx b/www/apps/resources/app/architectural-modules/notification/local/page.mdx index 48e2b8a7b5540..98ab18d4ea2d4 100644 --- a/www/apps/resources/app/architectural-modules/notification/local/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/local/page.mdx @@ -33,7 +33,7 @@ Only one provider can be defined for a channel. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -47,12 +47,9 @@ module.exports = defineConfig({ // ... { resolve: "@medusajs/notification-local", + id: "local", options: { - config: { - local: { - channels: ["email"], - }, - }, + channels: ["email"], }, }, ], diff --git a/www/apps/resources/app/architectural-modules/notification/page.mdx b/www/apps/resources/app/architectural-modules/notification/page.mdx index ce9f1e0e57216..e0ea59d1564c5 100644 --- a/www/apps/resources/app/architectural-modules/notification/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/page.mdx @@ -31,7 +31,7 @@ When you send a notification, you specify the channel to send it through, such a For example: ```js title="medusa-config.js" highlights={[["19"]]} -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -46,12 +46,9 @@ module.exports = { // ... { resolve: "@medusajs/notification-local", + id: "notification", options: { - config: { - local: { - channels: ["email"], - }, - }, + channels: ["email"], }, }, ], 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 index b35b7f3d6b0a2..22979153f2dc3 100644 --- a/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx @@ -33,7 +33,10 @@ export const highlights = [ ] ```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" -import type { SubscriberArgs, SubscriberConfig } from "@medusajs/medusa" +import type { + SubscriberArgs, + SubscriberConfig, +} from "@medusajs/medusa" import { ModuleRegistrationName } from "@medusajs/utils" import { INotificationModuleService } from "@medusajs/types" diff --git a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx index 28df88b26e1d0..4f48719b08fd6 100644 --- a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx @@ -35,7 +35,7 @@ Only one provider can be defined for a channel. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -49,14 +49,11 @@ module.exports = defineConfig({ // ... { resolve: "@medusajs/notification-sendgrid", + id: "sendgrid", options: { - config: { - sendgrid: { - channels: ["email"], - api_key: process.env.SENDGRID_API_KEY, - from: process.env.SENDGRID_FROM, - }, - }, + channels: ["email"], + api_key: process.env.SENDGRID_API_KEY, + from: process.env.SENDGRID_FROM, }, }, ], @@ -130,7 +127,10 @@ export const highlights = [ ] ```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" -import type { SubscriberArgs, SubscriberConfig } from "@medusajs/medusa" +import type { + SubscriberArgs, + SubscriberConfig, +} from "@medusajs/medusa" import { ModuleRegistrationName } from "@medusajs/utils" import { INotificationModuleService } from "@medusajs/types" diff --git a/www/apps/resources/app/architectural-modules/workflow-engine/in-memory/page.mdx b/www/apps/resources/app/architectural-modules/workflow-engine/in-memory/page.mdx index e997beabcd5ee..cc0873be6c766 100644 --- a/www/apps/resources/app/architectural-modules/workflow-engine/in-memory/page.mdx +++ b/www/apps/resources/app/architectural-modules/workflow-engine/in-memory/page.mdx @@ -31,7 +31,7 @@ npm install @medusajs/workflow-engine-inmemory Next, add the module into the `modules` property of the exported object in `medusa-config.js`: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx b/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx index 134cf96ded3a4..64383890c180f 100644 --- a/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx +++ b/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx @@ -31,7 +31,7 @@ export const highlights = [ ] ```js title="medusa-config.js" highlights={highlights} -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -42,7 +42,7 @@ module.exports = defineConfig({ resolve: "@medusajs/workflow-engine-redis", options: { redis: { - url: process.emv.WE_REDIS_URL, + url: process.env.WE_REDIS_URL, }, }, }, diff --git a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx index 2c21870a0deb0..1eb1907ec0703 100644 --- a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the API Key Modu -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( @@ -68,10 +68,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( @@ -172,10 +172,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const apiKeyModuleService: IApiKeyModuleService = request.scope.resolve( @@ -229,10 +229,13 @@ export async function POST(request: Request, { params }: ContextType) { -```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" -import { AuthenticatedMedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" + import { + AuthenticatedMedusaRequest, + MedusaResponse, + } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: AuthenticatedMedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/api-key/page.mdx b/www/apps/resources/app/commerce-modules/api-key/page.mdx index 94617942076c6..457485bb62fe6 100644 --- a/www/apps/resources/app/commerce-modules/api-key/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/page.mdx @@ -83,10 +83,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -105,10 +105,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const apiKeyModuleService: IApiKeyModuleService = container.resolve( @@ -122,10 +122,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IApiKeyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IApiKeyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const apiKeyModuleService: IApiKeyModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx index 93c6588d10c9e..fbc166db6eaa4 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx @@ -37,7 +37,7 @@ npm install @medusajs/auth-google Next, add the module to the array of providers passed to the Auth Module: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -49,16 +49,13 @@ const modules = { providers: [ { resolve: "@medusajs/auth-google", + id: "google", options: { - config: { - google: { - clientID: process.env.GOOGLE_CLIENT_ID, - clientSecret: process.env.GOOGLE_CLIENT_SECRET, - callbackURL: process.env.GOOGLE_CALLBACK_URL, - successRedirectUrl: - process.env.GOOGLE_SUCCESS_REDIRECT_URL, - }, - }, + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: process.env.GOOGLE_CALLBACK_URL, + successRedirectUrl: + process.env.GOOGLE_SUCCESS_REDIRECT_URL, }, }, ], diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx index ca331910000fe..af2ccbb1e9285 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx @@ -21,7 +21,7 @@ The Emailpass auth provider is registered by default with the Auth Module. If you want to pass options to the provider, add the provider to the `providers` option of the Auth Module: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -33,10 +33,9 @@ const modules = { providers: [ { resolve: "@medusajs/auth-emailpass", - config: { - emailpass: { - // options... - }, + id: "emailpass", + options: { + // options... }, }, ], 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 842bef26906e6..b621197792900 100644 --- a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx @@ -19,12 +19,15 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j -```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService, AuthenticationInput } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" -import { MedusaError } from "@medusajs/utils" -import jwt from "jsonwebtoken" + ```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { + IAuthModuleService, + AuthenticationInput, + } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" + import { MedusaError } from "@medusajs/utils" + import jwt from "jsonwebtoken" export async function POST( req: MedusaRequest, @@ -120,12 +123,15 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j -```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService, AuthenticationInput } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" -import { MedusaError } from "@medusajs/utils" -import jwt from "jsonwebtoken" + ```ts collapsibleLines="1-10" expandButtonLabel="Show Imports" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { + IAuthModuleService, + AuthenticationInput, + } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" + import { MedusaError } from "@medusajs/utils" + import jwt from "jsonwebtoken" export async function POST( req: MedusaRequest, @@ -219,10 +225,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IAuthModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -275,10 +281,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IAuthModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -321,10 +327,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IAuthModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -387,10 +393,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IAuthModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IAuthModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, 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 dfaa96ff462ec..8627886745bf3 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 @@ -21,7 +21,7 @@ When the Medusa application starts, these providers are registered and can be us For example: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -32,13 +32,10 @@ module.exports = defineConfig({ options: { providers: [ { - resolve: "@medusajs/auth-google", + resolve: "@medusajs/auth-emailpass", + id: "emailpass", options: { - config: { - google: { - // provider options... - }, - }, + // provider options... }, }, ], @@ -50,8 +47,8 @@ module.exports = defineConfig({ The `providers` option is an array of objects that accept the following properties: - `resolve`: A string indicating the package name of the module provider or the path to it. -- `options`: An optional object of the module provider's options. The object must have the following property: - - `config`: An object whose key is the ID of the auth provider, and its value is an object of options to pass to the module provider. +- `id`: A string indicating the provider's unique name or ID. +- `options`: An optional object of the module provider's options. --- diff --git a/www/apps/resources/app/commerce-modules/cart/examples/page.mdx b/www/apps/resources/app/commerce-modules/cart/examples/page.mdx index f0135d5b77ff3..83d522aaebea9 100644 --- a/www/apps/resources/app/commerce-modules/cart/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Cart Module -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -87,10 +87,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -135,10 +135,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -195,10 +195,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -253,10 +253,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -311,10 +311,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -371,10 +371,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, @@ -415,10 +415,10 @@ export async function DELETE(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, @@ -437,10 +437,10 @@ export async function DELETE( -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/cart/page.mdx b/www/apps/resources/app/commerce-modules/cart/page.mdx index 3eecd9a2b9c30..162e5c26d405d 100644 --- a/www/apps/resources/app/commerce-modules/cart/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/page.mdx @@ -71,10 +71,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -93,10 +93,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const cartModuleService: ICartModuleService = container.resolve( @@ -110,10 +110,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { ICartModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { ICartModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const cartModuleService: ICartModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/currency/examples/page.mdx b/www/apps/resources/app/commerce-modules/currency/examples/page.mdx index 3fd7f4ac10693..1f61a02ef35a6 100644 --- a/www/apps/resources/app/commerce-modules/currency/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/currency/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Currency Mod -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICurrencyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICurrencyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -59,10 +59,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICurrencyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICurrencyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/currency/page.mdx b/www/apps/resources/app/commerce-modules/currency/page.mdx index 7462a6c04b31e..fc2603fb26c34 100644 --- a/www/apps/resources/app/commerce-modules/currency/page.mdx +++ b/www/apps/resources/app/commerce-modules/currency/page.mdx @@ -42,10 +42,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICurrencyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICurrencyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -64,10 +64,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { ICurrencyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { ICurrencyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const currencyModuleService: ICurrencyModuleService = container.resolve( @@ -81,10 +81,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { ICurrencyModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { ICurrencyModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const currencyModuleService: ICurrencyModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/customer/examples/page.mdx b/www/apps/resources/app/commerce-modules/customer/examples/page.mdx index 8d093514a5cec..82428f368e059 100644 --- a/www/apps/resources/app/commerce-modules/customer/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/customer/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Customer Mod -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const customerModuleService: ICustomerModuleService = request.scope.resolve( @@ -68,10 +68,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const customerModuleService: ICustomerModuleService = request.scope.resolve( @@ -119,10 +119,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const customerModuleService: ICustomerModuleService = request.scope.resolve( @@ -168,10 +168,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const customerModuleService: ICustomerModuleService = request.scope.resolve( diff --git a/www/apps/resources/app/commerce-modules/customer/page.mdx b/www/apps/resources/app/commerce-modules/customer/page.mdx index 5c4330521398c..418d29e91973f 100644 --- a/www/apps/resources/app/commerce-modules/customer/page.mdx +++ b/www/apps/resources/app/commerce-modules/customer/page.mdx @@ -48,10 +48,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const customerModuleService: ICustomerModuleService = request.scope.resolve( @@ -67,10 +67,10 @@ export async function GET(request: MedusaRequest, res: MedusaResponse) { -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const customerModuleService: ICustomerModuleService = container.resolve( @@ -84,10 +84,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { ICustomerModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { ICustomerModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const customerModuleService: ICustomerModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/fulfillment/module-options/page.mdx b/www/apps/resources/app/commerce-modules/fulfillment/module-options/page.mdx index 86bcd43f55cf2..496eddfd51c58 100644 --- a/www/apps/resources/app/commerce-modules/fulfillment/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/fulfillment/module-options/page.mdx @@ -21,7 +21,7 @@ When the Medusa application starts, these providers are registered and can be us For example: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -34,12 +34,9 @@ module.exports = defineConfig({ providers: [ { resolve: `@medusajs/fulfillment-manual`, + name: "manual", options: { - config: { - manual: { - // provider options... - }, - }, + // provider options... }, }, ], @@ -52,5 +49,5 @@ module.exports = defineConfig({ The `providers` option is an array of objects that accept the following properties: - `resolve`: A string indicating either the package name of the module provider or the path to it relative to the `src` directory. -- `options`: An optional object of the module provider's options. The object must have the following property: - - `config`: An object whose key is the ID of the module provider, and its value is an object of options to pass to the module provider. \ No newline at end of file +- `name`: A string indicating the provider's unique name. +- `options`: An optional object of the module provider's options. diff --git a/www/apps/resources/app/commerce-modules/fulfillment/page.mdx b/www/apps/resources/app/commerce-modules/fulfillment/page.mdx index 368cfa1662242..8c9b9275c38ac 100644 --- a/www/apps/resources/app/commerce-modules/fulfillment/page.mdx +++ b/www/apps/resources/app/commerce-modules/fulfillment/page.mdx @@ -113,10 +113,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IFulfillmentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IFulfillmentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -135,10 +135,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IFulfillmentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IFulfillmentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const fulfillmentModuleService: IFulfillmentModuleService = container.resolve( @@ -152,10 +152,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IFulfillmentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IFulfillmentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const fulfillmentModuleService: IFulfillmentModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx b/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx index 1234e5f78752d..7abc7890abdee 100644 --- a/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/inventory/examples/page.mdx @@ -13,10 +13,10 @@ In this document, you’ll find common examples of how you can use the Inventory -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -68,10 +68,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -114,10 +114,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -170,10 +170,10 @@ export async function GET(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -225,10 +225,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -280,10 +280,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -335,10 +335,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -392,10 +392,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -479,10 +479,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/inventory/page.mdx b/www/apps/resources/app/commerce-modules/inventory/page.mdx index 4d7255ed835c1..793815a5ec384 100644 --- a/www/apps/resources/app/commerce-modules/inventory/page.mdx +++ b/www/apps/resources/app/commerce-modules/inventory/page.mdx @@ -75,10 +75,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -97,10 +97,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const inventoryModuleService: IInventoryService = container.resolve( @@ -114,10 +114,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IInventoryService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IInventoryService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const inventoryModuleService: IInventoryService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/order/page.mdx b/www/apps/resources/app/commerce-modules/order/page.mdx index 519fe18df8925..4bd2d898ce6fe 100644 --- a/www/apps/resources/app/commerce-modules/order/page.mdx +++ b/www/apps/resources/app/commerce-modules/order/page.mdx @@ -107,10 +107,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IOrderModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IOrderModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -129,10 +129,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IOrderModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IOrderModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const orderModuleService: IOrderModuleService = container.resolve( @@ -146,10 +146,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IOrderModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IOrderModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const orderModuleService: IOrderModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/payment/examples/page.mdx b/www/apps/resources/app/commerce-modules/payment/examples/page.mdx index fdb946bbd6296..23918e7351dec 100644 --- a/www/apps/resources/app/commerce-modules/payment/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/payment/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Payment Modu -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -75,10 +75,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -141,10 +141,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -195,10 +195,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -251,10 +251,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -305,10 +305,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/payment/module-options/page.mdx b/www/apps/resources/app/commerce-modules/payment/module-options/page.mdx index f67f18b69f068..55bde78e30a35 100644 --- a/www/apps/resources/app/commerce-modules/payment/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/payment/module-options/page.mdx @@ -104,7 +104,7 @@ When the Medusa application starts, these providers are registered and can be us For example: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -117,6 +117,7 @@ module.exports = defineConfig({ providers: [ { resolve: "@medusajs/payment-stripe", + id: "stripe", options: { // ... }, @@ -131,5 +132,5 @@ module.exports = defineConfig({ The `providers` option is an array of objects that accept the following properties: - `resolve`: A string indicating the package name of the module provider or the path to it relative to the `src` directory. -- `options`: An optional object of the module provider's options. The object must have the following property: - - `config`: An object whose key is the ID of the module provider, and its value is an object of options to pass to the module provider. \ No newline at end of file +- `id`: A string indicating the provider's unique name or ID. +- `options`: An optional object of the module provider's options. \ No newline at end of file diff --git a/www/apps/resources/app/commerce-modules/payment/page.mdx b/www/apps/resources/app/commerce-modules/payment/page.mdx index de105d094ee96..b315f8f977679 100644 --- a/www/apps/resources/app/commerce-modules/payment/page.mdx +++ b/www/apps/resources/app/commerce-modules/payment/page.mdx @@ -80,10 +80,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -102,10 +102,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const paymentModuleService: IPaymentModuleService = container.resolve( @@ -120,10 +120,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IPaymentModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IPaymentModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const paymentModuleService: IPaymentModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/payment/payment-provider/stripe/page.mdx b/www/apps/resources/app/commerce-modules/payment/payment-provider/stripe/page.mdx index 035f7375634c2..b0c3d065151a5 100644 --- a/www/apps/resources/app/commerce-modules/payment/payment-provider/stripe/page.mdx +++ b/www/apps/resources/app/commerce-modules/payment/payment-provider/stripe/page.mdx @@ -25,7 +25,7 @@ These features are also available in a safe test environment, allowing for a con - [Stripe account](https://stripe.com/). -- [Stripe API Key](https://support.stripe.com/questions/locate-api-keys-in-the-dashboard) +- [Stripe Secret API Key](https://support.stripe.com/questions/locate-api-keys-in-the-dashboard) - For deployed Medusa applications, a [Stripe webhook secret](https://docs.stripe.com/webhooks#add-a-webhook-endpoint). When creating the Webhook, set the endpoint URL to `{medusa_url}/hooks/payment/stripe`, where `{medusa_url}` with the URL to your deployed Medusa application. @@ -39,7 +39,7 @@ npm install @medusajs/payment-stripe Next, add the module to the array of providers passed to the Payment Module: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -52,16 +52,9 @@ module.exports = defineConfig({ providers: [ { resolve: "@medusajs/payment-stripe", + id: "stripe", options: { - config: { - stripe: { - credentials: { - usd: { - apiKey: process.env.STRIPE_USD_API_KEY, - }, - }, - }, - }, + apiKey: process.env.STRIPE_API_KEY, }, }, ], @@ -76,7 +69,7 @@ module.exports = defineConfig({ Make sure to add the necessary environment variables for the above options in `.env`: ```bash -STRIPE_USD_API_KEY= +STRIPE_API_KEY= ``` ### Module Options @@ -94,17 +87,12 @@ STRIPE_USD_API_KEY= - `credentials` + `apiKey` - An object where each entry is a stripe provider installation. The object’s keys are the name suffix of the provider, where the provider name will be formatted as `stripe-{key}`. For example, `stripe-usd`. - - Each value is an object that accepts the following properties: - - - `apiKey`: A string indicating the Stripe API key. - - `webhookSecret`: (optional in development) A string indicating the Stripe webhook secret. This is only useful for deployed Medusa applications. + A string indicating the Stripe Secret API key. @@ -114,7 +102,29 @@ STRIPE_USD_API_KEY= - \- + - + + + + + + + `webhookSecret` + + + + + A string indicating the Stripe webhook secret. This is only useful for deployed Medusa applications. + + + + + Yes + + + + + - diff --git a/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx b/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx index 67b19292b7006..7d0d2fa2ee64f 100644 --- a/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx @@ -13,10 +13,10 @@ In this document, you’ll find common examples of how you can use the Pricing M -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -84,10 +84,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -130,10 +130,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -176,10 +176,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -245,11 +245,11 @@ export async function POST(request: Request) { -```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { PriceListType } from "@medusajs/utils" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { PriceListType } from "@medusajs/utils" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -330,10 +330,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/pricing/page.mdx b/www/apps/resources/app/commerce-modules/pricing/page.mdx index 9cffcba0a066f..d922fd8ad1f3c 100644 --- a/www/apps/resources/app/commerce-modules/pricing/page.mdx +++ b/www/apps/resources/app/commerce-modules/pricing/page.mdx @@ -106,10 +106,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -128,10 +128,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const pricingModuleService: IPricingModuleService = container.resolve( @@ -145,10 +145,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IPricingModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IPricingModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const pricingModuleService: IPricingModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/product/examples/page.mdx b/www/apps/resources/app/commerce-modules/product/examples/page.mdx index 4d13294eade1f..326c9b4f75f04 100644 --- a/www/apps/resources/app/commerce-modules/product/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/product/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Product Modu -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -94,10 +94,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -137,10 +137,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -184,10 +184,10 @@ export async function GET( -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -231,10 +231,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -274,10 +274,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( diff --git a/www/apps/resources/app/commerce-modules/product/page.mdx b/www/apps/resources/app/commerce-modules/product/page.mdx index eb33795edda3f..ee740c07c744e 100644 --- a/www/apps/resources/app/commerce-modules/product/page.mdx +++ b/www/apps/resources/app/commerce-modules/product/page.mdx @@ -69,10 +69,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET(request: MedusaRequest, res: MedusaResponse) { const productModuleService: IProductModuleService = request.scope.resolve( @@ -88,10 +88,10 @@ export async function GET(request: MedusaRequest, res: MedusaResponse) { -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const productModuleService: IProductModuleService = container.resolve( @@ -105,10 +105,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IProductModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const productModuleService: IProductModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx b/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx index e8b83a3aa4a56..599f10f6db45b 100644 --- a/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/promotion/examples/page.mdx @@ -13,10 +13,10 @@ In this document, you’ll find common examples of how you can use the Promotion -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -78,10 +78,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -135,10 +135,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -213,10 +213,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/promotion/page.mdx b/www/apps/resources/app/commerce-modules/promotion/page.mdx index fe2fe1db82c59..f261789ddd714 100644 --- a/www/apps/resources/app/commerce-modules/promotion/page.mdx +++ b/www/apps/resources/app/commerce-modules/promotion/page.mdx @@ -79,10 +79,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -101,10 +101,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const promotionModuleService: IPromotionModuleService = container.resolve( @@ -118,10 +118,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IPromotionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IPromotionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const promotionModuleService: IPromotionModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/region/examples/page.mdx b/www/apps/resources/app/commerce-modules/region/examples/page.mdx index c48d10a4eff97..3b309387977cf 100644 --- a/www/apps/resources/app/commerce-modules/region/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/region/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Region Modul -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -69,10 +69,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -115,10 +115,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -161,10 +161,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -211,10 +211,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/region/page.mdx b/www/apps/resources/app/commerce-modules/region/page.mdx index e016c53e2bebb..60cae41d85f66 100644 --- a/www/apps/resources/app/commerce-modules/region/page.mdx +++ b/www/apps/resources/app/commerce-modules/region/page.mdx @@ -76,10 +76,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -98,10 +98,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const regionModuleService: IRegionModuleService = container.resolve( @@ -115,10 +115,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IRegionModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IRegionModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const regionModuleService: IRegionModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx b/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx index fe9fffb3b0204..e422095196334 100644 --- a/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/sales-channel/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Sales Channe -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -64,10 +64,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -109,10 +109,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -160,10 +160,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -213,10 +213,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/sales-channel/page.mdx b/www/apps/resources/app/commerce-modules/sales-channel/page.mdx index b49323e6b30c7..71543e5edb1dd 100644 --- a/www/apps/resources/app/commerce-modules/sales-channel/page.mdx +++ b/www/apps/resources/app/commerce-modules/sales-channel/page.mdx @@ -60,10 +60,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -81,10 +81,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const salesChannelModuleService: ISalesChannelModuleService = @@ -97,10 +97,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { ISalesChannelModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { ISalesChannelModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const salesChannelModuleService: ISalesChannelModuleService = diff --git a/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx b/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx index 6fa155d727404..dfc19eeb5c179 100644 --- a/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/stock-location/examples/page.mdx @@ -13,10 +13,10 @@ In this document, you’ll find common examples of how you can use the Stock Loc -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -64,10 +64,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -109,10 +109,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -174,10 +174,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/stock-location/page.mdx b/www/apps/resources/app/commerce-modules/stock-location/page.mdx index d300de5cc64a5..c462567a46f21 100644 --- a/www/apps/resources/app/commerce-modules/stock-location/page.mdx +++ b/www/apps/resources/app/commerce-modules/stock-location/page.mdx @@ -47,10 +47,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -68,10 +68,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const stockLocationModuleService: IStockLocationService = container.resolve( @@ -85,10 +85,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IStockLocationService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IStockLocationService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const stockLocationModuleService: IStockLocationService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/store/examples/page.mdx b/www/apps/resources/app/commerce-modules/store/examples/page.mdx index 332cfbe0863ba..fe56e6a08f311 100644 --- a/www/apps/resources/app/commerce-modules/store/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/store/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Store Module -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -79,10 +79,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -127,10 +127,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -175,10 +175,10 @@ export async function GET(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( request: MedusaRequest, @@ -227,10 +227,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( request: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/store/page.mdx b/www/apps/resources/app/commerce-modules/store/page.mdx index b63a708186854..46ace11b10efb 100644 --- a/www/apps/resources/app/commerce-modules/store/page.mdx +++ b/www/apps/resources/app/commerce-modules/store/page.mdx @@ -49,10 +49,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( request: MedusaRequest, @@ -71,10 +71,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const storeModuleService: IStoreModuleService = container.resolve( @@ -88,10 +88,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IStoreModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IStoreModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const storeModuleService: IStoreModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/tax/examples/page.mdx b/www/apps/resources/app/commerce-modules/tax/examples/page.mdx index 29b2fa6f7c84f..05fa2d48ee365 100644 --- a/www/apps/resources/app/commerce-modules/tax/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/tax/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the Tax Module i -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -75,10 +75,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -121,10 +121,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -199,10 +199,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -245,10 +245,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/tax/module-options/page.mdx b/www/apps/resources/app/commerce-modules/tax/module-options/page.mdx index 5b5ba896127dd..8402f2cf13484 100644 --- a/www/apps/resources/app/commerce-modules/tax/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/tax/module-options/page.mdx @@ -19,7 +19,7 @@ The `providers` option is an array of either tax module providers, tax plugins, When the Medusa application starts, these providers are registered and can be used to retrieve tax lines. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -31,7 +31,8 @@ module.exports = defineConfig({ options: { providers: [ { - resolve: "my-provider", + resolve: "./path/to/my-provider", + id: "my-provider", options: { // ... }, @@ -46,4 +47,5 @@ module.exports = defineConfig({ The objects in the array accept the following properties: - `resolve`: A string indicating the package name of the module provider or the path to it relative to the `src` directory. -- `options`: An object of options to pass to the module provider. +- `id`: A string indicating the provider's unique name or ID. +- `options`: An optional object of the module provider's options. diff --git a/www/apps/resources/app/commerce-modules/tax/page.mdx b/www/apps/resources/app/commerce-modules/tax/page.mdx index 67fe4f4f16887..7c503d7c5872f 100644 --- a/www/apps/resources/app/commerce-modules/tax/page.mdx +++ b/www/apps/resources/app/commerce-modules/tax/page.mdx @@ -91,10 +91,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -113,10 +113,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const taxModuleService: ITaxModuleService = container.resolve( @@ -130,10 +130,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { ITaxModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { ITaxModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const taxModuleService: ITaxModuleService = container.resolve( diff --git a/www/apps/resources/app/commerce-modules/user/examples/page.mdx b/www/apps/resources/app/commerce-modules/user/examples/page.mdx index 4748db8a94a19..b04be256845e2 100644 --- a/www/apps/resources/app/commerce-modules/user/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/user/examples/page.mdx @@ -13,10 +13,10 @@ In this guide, you’ll find common examples of how you can use the User Module -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -69,10 +69,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -115,10 +115,10 @@ export async function GET(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -169,10 +169,10 @@ export async function POST(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function DELETE( req: MedusaRequest, @@ -211,10 +211,10 @@ export async function DELETE(request: Request) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -265,10 +265,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, @@ -335,10 +335,10 @@ export async function POST(request: Request, { params }: ContextType) { -```ts -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function POST( req: MedusaRequest, diff --git a/www/apps/resources/app/commerce-modules/user/module-options/page.mdx b/www/apps/resources/app/commerce-modules/user/module-options/page.mdx index 80a77d99e683e..a37dd43d58c67 100644 --- a/www/apps/resources/app/commerce-modules/user/module-options/page.mdx +++ b/www/apps/resources/app/commerce-modules/user/module-options/page.mdx @@ -15,7 +15,7 @@ In this document, you'll learn about the options of the User Module. ## Module Options ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/app/commerce-modules/user/page.mdx b/www/apps/resources/app/commerce-modules/user/page.mdx index 2fa2bb8daaeb1..46c49802f718b 100644 --- a/www/apps/resources/app/commerce-modules/user/page.mdx +++ b/www/apps/resources/app/commerce-modules/user/page.mdx @@ -52,10 +52,10 @@ For example: -```ts title="src/api/store/custom/route.ts" -import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/api/store/custom/route.ts" + import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export async function GET( req: MedusaRequest, @@ -74,10 +74,10 @@ export async function GET( -```ts title="src/subscribers/custom-handler.ts" -import { SubscriberArgs } from "@medusajs/medusa" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/subscribers/custom-handler.ts" + import { SubscriberArgs } from "@medusajs/medusa" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" export default async function subscriberHandler({ container }: SubscriberArgs) { const userModuleService: IUserModuleService = container.resolve( @@ -91,10 +91,10 @@ export default async function subscriberHandler({ container }: SubscriberArgs) { -```ts title="src/workflows/hello-world/step1.ts" -import { createStep } from "@medusajs/workflows-sdk" -import { IUserModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" + ```ts title="src/workflows/hello-world/step1.ts" + import { createStep } from "@medusajs/workflows-sdk" + import { IUserModuleService } from "@medusajs/types" + import { ModuleRegistrationName } from "@medusajs/utils" const step1 = createStep("step-1", async (_, { container }) => { const userModuleService: IUserModuleService = container.resolve( diff --git a/www/apps/resources/app/recipes/commerce-automation/page.mdx b/www/apps/resources/app/recipes/commerce-automation/page.mdx index 432f3f8061b9f..e97761245f50f 100644 --- a/www/apps/resources/app/recipes/commerce-automation/page.mdx +++ b/www/apps/resources/app/recipes/commerce-automation/page.mdx @@ -976,4 +976,4 @@ export const newsletterHighlights = [ 5. Use the Notification Module to send a notification to the customer. This uses the Notification Module Provider configured for the `email` channel. 6. Update the store's `last_newsletter_send_date` with the current date. -
\ No newline at end of file + diff --git a/www/apps/resources/app/recipes/integrate-ecommerce-stack/page.mdx b/www/apps/resources/app/recipes/integrate-ecommerce-stack/page.mdx index 122de33607b84..623a62eb53cc9 100644 --- a/www/apps/resources/app/recipes/integrate-ecommerce-stack/page.mdx +++ b/www/apps/resources/app/recipes/integrate-ecommerce-stack/page.mdx @@ -74,13 +74,13 @@ export const serviceHighlights = [ async getProductData(id: string) { const { data: erpProduct } = await this.client_.get(`/product/${id}`) - + return erpProduct } async createProduct(data: ProductDTO) { const { data: erpProduct } = await this.client_.post(`/product`, data) - + return erpProduct } @@ -90,7 +90,6 @@ export const serviceHighlights = [ } export default ErpModuleService - ``` This creates the module's main service. Few things to note: @@ -111,11 +110,12 @@ export const serviceHighlights = [ ```ts title="src/modules/erp/index.ts" import ErpModuleService from "./service" + import { Module } from "@medusajs/utils" - export default { + export default Module("erp", { service: ErpModuleService, - } - ```` + }) + ``` Finally, add the module to the `modules` object in `medusa-config.js`: @@ -134,7 +134,7 @@ export const serviceHighlights = [ ``` - + --- @@ -168,28 +168,12 @@ export const workflowHighlights = [ ["24", "productModuleService", "Resolve the Product Module's main service."], ["28", "retrieve", "Retrieve the created product's data."], ["30", "createProduct", "Create the product in the ERP system."], - [ - "34", - "update", - "Update the product in Medusa with the ID of the ERP product.", - ], + ["34", "update", "Update the product in Medusa with the ID of the ERP product."], ["43", "erpId", "Pass the ERP product's ID to the compensation function."], ["44", "productId", "Pass the product's ID to the compensation function."], - [ - "46", - "", - "Define a compensation function that rolls back changes when an error occurs.", - ], - [ - "53", - "deleteProduct", - "Undo creating the product in the ERP system by deleting it.", - ], - [ - "54", - "update", - "Update the product in Medusa to remove the ERP product's ID.", - ], + ["46", "", "Define a compensation function that rolls back changes when an error occurs."], + ["53", "deleteProduct", "Undo creating the product in the ERP system by deleting it."], + ["54", "update", "Update the product in Medusa to remove the ERP product's ID."] ] ```ts title="src/workflows/create-product.ts" highlights={workflowHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports" @@ -211,14 +195,14 @@ export const workflowHighlights = [ } const createInErpStep = createStep( - "create-in-erp", + "create-in-erp", async ({ productId }: WorkflowInput, { container }) => { const erpModuleService: ErpModuleService = container.resolve( "erpModuleService" ) const productModuleService: IProductModuleService = container .resolve(ModuleRegistrationName.PRODUCT) - + const createdProductData = await productModuleService .retrieveProduct(productId) @@ -231,7 +215,7 @@ export const workflowHighlights = [ erp_id: erpProduct.id } }) - + return new StepResponse({ erpProduct }, { @@ -267,20 +251,20 @@ export const workflowHighlights = [ - Retrieves the product's data using the Product Module's main service. - Create the product in the ERP system using the ERP Module's main service. - Updates the product in Medusa by setting the ID of the ERP product in the product's `metadata` property. - + The step also has a compensation function that rolls back changes when an error occurs. It deletes the product in the ERP system and removes the ID of the ERP product in the Medusa product. - + Then, create the subscriber at `src/subscribers/create-product.ts`: ```ts title="src/subscribers/create-product.ts" - import type { - SubscriberConfig, + import type { + SubscriberConfig, SubscriberArgs, } from "@medusajs/medusa" import createProductWorkflow from "../workflows/create-product" - export default async function handleProductUpdate({ - data, container + export default async function handleProductUpdate({ + data, container }: SubscriberArgs<{id: string}>) { createProductWorkflow(container) .run({ @@ -323,12 +307,12 @@ For example, suppose an administrator changes the product data in the ERP system For example, create the file `src/api/webhooks/erp/update/route.ts` with the following content: ```ts title="src/api/webhooks/erp/update/route.ts" collapsibleLines="1-12" expandButtonLabel="Show Imports" - import { - MedusaRequest, - MedusaResponse, + import { + MedusaRequest, + MedusaResponse, } from "@medusajs/medusa" - import { - IProductModuleService, + import { + IProductModuleService, UpdateProductDTO } from "@medusajs/types" import { @@ -341,7 +325,7 @@ For example, suppose an administrator changes the product data in the ERP system } export async function POST( - req: MedusaRequest, + req: MedusaRequest, res: MedusaResponse ) { const { id, updatedData} = req.body @@ -356,15 +340,15 @@ For example, suppose an administrator changes the product data in the ERP system res.status(200) } ``` - + This creates a webhook listener for an ERP system. It receives the ID of a product and its updated data, assuming that’s how your ERP system sends the data. - + Then, create the file `src/api/middlewares.ts` with the following content: ```ts title="src/api/middlewares.ts" import { MiddlewaresConfig } from "@medusajs/medusa" import { raw } from "body-parser" - + export const config: MiddlewaresConfig = { routes: [ { diff --git a/www/apps/resources/app/recipes/marketplace/page.mdx b/www/apps/resources/app/recipes/marketplace/page.mdx index 2e13cd6fdf873..62e1d9dd38314 100644 --- a/www/apps/resources/app/recipes/marketplace/page.mdx +++ b/www/apps/resources/app/recipes/marketplace/page.mdx @@ -821,4 +821,4 @@ For example, you can create an API route that retrieves available stores and ano startIcon: , showLinkIcon: false }, -]} /> \ No newline at end of file +]} /> diff --git a/www/apps/resources/app/recipes/pos/page.mdx b/www/apps/resources/app/recipes/pos/page.mdx index 01df442e6435f..a966f5facf78a 100644 --- a/www/apps/resources/app/recipes/pos/page.mdx +++ b/www/apps/resources/app/recipes/pos/page.mdx @@ -75,11 +75,14 @@ To search through product variants by their barcode, create a custom API Route a Here’s an example of creating a custom API Route at `/store/pos/search-barcode` that searches product variants by a barcode: -```ts title="src/api/store/pos/search-barcode/route.ts" collapsibleLines="1-8" expandButtonLabel="Show Imports" -import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa" -import { MedusaError } from "@medusajs/utils" -import { ModuleRegistrationName } from "@medusajs/utils" -import { IProductModuleService } from "@medusajs/types" + ```ts title="src/api/store/pos/search-barcode/route.ts" collapsibleLines="1-8" expandButtonLabel="Show Imports" + import type { + MedusaRequest, + MedusaResponse, + } from "@medusajs/medusa" + import { MedusaError } from "@medusajs/utils" + import { ModuleRegistrationName } from "@medusajs/utils" + import { IProductModuleService } from "@medusajs/types" export const GET = async (req: MedusaRequest, res: MedusaResponse) => { const barcode = (req.query.barcode as string) || "" diff --git a/www/apps/resources/package.json b/www/apps/resources/package.json index c439d7c8f8834..7e41f4827aa35 100644 --- a/www/apps/resources/package.json +++ b/www/apps/resources/package.json @@ -45,5 +45,8 @@ "tsconfig": "*", "types": "*", "typescript": "^5" + }, + "engines": { + "node": ">=20" } } diff --git a/www/apps/resources/references/auth_provider/classes/auth_provider.AbstractAuthModuleProvider/page.mdx b/www/apps/resources/references/auth_provider/classes/auth_provider.AbstractAuthModuleProvider/page.mdx index 77672a694f563..f4576ff134ab3 100644 --- a/www/apps/resources/references/auth_provider/classes/auth_provider.AbstractAuthModuleProvider/page.mdx +++ b/www/apps/resources/references/auth_provider/classes/auth_provider.AbstractAuthModuleProvider/page.mdx @@ -298,7 +298,7 @@ This exports the module's definition, indicating that the `MyAuthProviderService To use your Auth Provider Module, add it to the `providers` array of the Auth Module: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... 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 daccde7a24d61..07183dd3d7f12 100644 --- a/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx +++ b/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx @@ -194,7 +194,7 @@ The File Module accepts one provider only. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/references/fulfillment_provider/classes/fulfillment_provider.AbstractFulfillmentProviderService/page.mdx b/www/apps/resources/references/fulfillment_provider/classes/fulfillment_provider.AbstractFulfillmentProviderService/page.mdx index 4d7990a0ac56a..543ac597fcd25 100644 --- a/www/apps/resources/references/fulfillment_provider/classes/fulfillment_provider.AbstractFulfillmentProviderService/page.mdx +++ b/www/apps/resources/references/fulfillment_provider/classes/fulfillment_provider.AbstractFulfillmentProviderService/page.mdx @@ -65,7 +65,7 @@ This exports the module's definition, indicating that the `MyFulfillmentProvider To use your Fulfillment Provider Module, add it to the `providers` array of the Fulfillment Module: ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx b/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx index 9a015dbcfab84..bf18b311296bc 100644 --- a/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx +++ b/www/apps/resources/references/notification/classes/notification.AbstractNotificationProviderService/page.mdx @@ -141,7 +141,7 @@ The Notification Module accepts one provider per channel. ```js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... diff --git a/www/apps/ui/package.json b/www/apps/ui/package.json index e384ccbbdcd8a..e8852969a1eb3 100644 --- a/www/apps/ui/package.json +++ b/www/apps/ui/package.json @@ -51,6 +51,6 @@ "types": "*" }, "engines": { - "node": ">=18.17.0" + "node": ">=20" } } diff --git a/www/apps/user-guide/package.json b/www/apps/user-guide/package.json index 3024f8f268ccf..8c30205fc807e 100644 --- a/www/apps/user-guide/package.json +++ b/www/apps/user-guide/package.json @@ -47,6 +47,6 @@ "typescript": "^5" }, "engines": { - "node": ">=18.17.0" + "node": ">=20" } } diff --git a/www/packages/docs-ui/src/components/ApiRunner/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/index.tsx index 5d7465be9d9be..1cd80c33a1f43 100644 --- a/www/packages/docs-ui/src/components/ApiRunner/index.tsx +++ b/www/packages/docs-ui/src/components/ApiRunner/index.tsx @@ -17,130 +17,128 @@ type ApiRunnerProps = { bodyData?: Record } -export const ApiRunner = ({ - apiMethod, - apiUrl, - pathData, - bodyData, - queryData, -}: ApiRunnerProps) => { - // assemble api testing options - const [apiTestingOptions, setApiTestingOptions] = useState( - { - method: apiMethod, - url: apiUrl, - pathData, - bodyData, - queryData, - } - ) - const [isRunning, setIsRunning] = useState(false) - const [ran, setRan] = useState(false) - const hasData = (data?: Record): boolean => - data !== undefined && Object.keys(data).length > 0 - // TODO change to be based on whether auth/data needed - const manualTestTrigger = useMemo( - () => - hasData(apiTestingOptions.pathData) || - hasData(apiTestingOptions.queryData) || - hasData(apiTestingOptions.bodyData), - [apiTestingOptions] - ) - const [responseLogs, setResponseLogs] = useState([]) - const [responseCode, setResponseCode] = useState() - const pushMessage = (...message: string[]) => - setResponseLogs((prev) => [...prev, ...message]) - const { runRequest } = useRequestRunner({ - pushLog: pushMessage, - onFinish: (_message, statusCode) => { - setIsRunning(false) - setResponseCode(statusCode) - }, - replaceLog: (message) => setResponseLogs([message]), - }) +export const ApiRunner = React.forwardRef( + function ApiRunner( + { apiMethod, apiUrl, pathData, bodyData, queryData }: ApiRunnerProps, + ref + ) { + // assemble api testing options + const [apiTestingOptions, setApiTestingOptions] = + useState({ + method: apiMethod, + url: apiUrl, + pathData, + bodyData, + queryData, + }) + const [isRunning, setIsRunning] = useState(false) + const [ran, setRan] = useState(false) + const hasData = (data?: Record): boolean => + data !== undefined && Object.keys(data).length > 0 + // TODO change to be based on whether auth/data needed + const manualTestTrigger = useMemo( + () => + hasData(apiTestingOptions.pathData) || + hasData(apiTestingOptions.queryData) || + hasData(apiTestingOptions.bodyData), + [apiTestingOptions] + ) + const [responseLogs, setResponseLogs] = useState([]) + const [responseCode, setResponseCode] = useState() + const pushMessage = (...message: string[]) => + setResponseLogs((prev) => [...prev, ...message]) + const { runRequest } = useRequestRunner({ + pushLog: pushMessage, + onFinish: (_message, statusCode) => { + setIsRunning(false) + setResponseCode(statusCode) + }, + replaceLog: (message) => setResponseLogs([message]), + }) - useEffect(() => { - if (!isRunning && !manualTestTrigger && !ran) { - setIsRunning(true) - } - }, [apiTestingOptions, manualTestTrigger, isRunning, ran]) + useEffect(() => { + if (!isRunning && !manualTestTrigger && !ran) { + setIsRunning(true) + } + }, [apiTestingOptions, manualTestTrigger, isRunning, ran]) - useEffect(() => { - if (isRunning && !ran) { - setRan(true) - setResponseLogs(["Sending request..."]) - runRequest(apiTestingOptions) - } - }, [isRunning, ran]) + useEffect(() => { + if (isRunning && !ran) { + setRan(true) + setResponseLogs(["Sending request..."]) + runRequest(apiTestingOptions) + } + }, [isRunning, ran]) - return ( - <> - {manualTestTrigger && ( - - {apiTestingOptions.pathData && ( - - > - } - /> - )} - {apiTestingOptions.bodyData && ( - - > - } - /> - )} - {apiTestingOptions.queryData && ( - - > - } - /> - )} - - - )} - {(isRunning || ran) && ( - - )} - - ) -} + return ( +
+ {manualTestTrigger && ( + + {apiTestingOptions.pathData && ( + + > + } + /> + )} + {apiTestingOptions.bodyData && ( + + > + } + /> + )} + {apiTestingOptions.queryData && ( + + > + } + /> + )} + + + )} + {(isRunning || ran) && ( + + )} +
+ ) + } +) diff --git a/www/packages/docs-ui/src/components/CodeBlock/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/index.tsx index 74ac6c903d94d..3f70c284c0498 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/index.tsx @@ -78,6 +78,7 @@ export const CodeBlock = ({ const [showTesting, setShowTesting] = useState(false) const codeContainerRef = useRef(null) const codeRef = useRef(null) + const apiRunnerRef = useRef(null) const [scrollable, setScrollable] = useState(false) const hasInnerCodeBlock = useMemo( () => hasTabs || title.length > 0, @@ -399,6 +400,7 @@ export const CodeBlock = ({ enter: "animate-fadeIn animate-fastest", exit: "animate-fadeOut animate-fastest", }} + nodeRef={apiRunnerRef} > )} diff --git a/www/packages/docs-ui/src/hooks/use-request-runner/index.ts b/www/packages/docs-ui/src/hooks/use-request-runner/index.ts index ad81776718a06..36099d0479330 100644 --- a/www/packages/docs-ui/src/hooks/use-request-runner/index.ts +++ b/www/packages/docs-ui/src/hooks/use-request-runner/index.ts @@ -48,12 +48,23 @@ export const useRequestRunner = ({ replaceLog ? replaceLog(stringifiedData) : pushLog(stringifiedData) }) .catch((error) => { - pushLog( - `An error ocurred: ${JSON.stringify(error, undefined, 2)}`, - `\nThis could be a CORS error. You can resolve it by adding\nthe docs' URLto your CORS configurations:\n`, - `STORE_CORS=http://localhost:8000,https://docs.medusajs.com`, - `ADMIN_CORS=http://localhost:7001,https://docs.medusajs.com` - ) + pushLog(`\nAn error ocurred: ${JSON.stringify(error, undefined, 2)}`) + if (responseCode === "404") { + pushLog( + `\nPossible Solutions:\n`, + `- If this is a custom API route, make sure you added it at the correct path.`, + `- If this API route accepts any parameters, such as an ID, make sure it exists\nin the Medusa application.` + ) + return + } + + if (!responseCode.length) { + pushLog( + `\nThis could be a CORS error. You can resolve it by adding\nthe docs' URLto your CORS configurations:\n`, + `STORE_CORS=http://localhost:8000,https://docs.medusajs.com`, + `ADMIN_CORS=http://localhost:7001,https://docs.medusajs.com` + ) + } }) .finally(() => onFinish(`Finished running request.`, responseCode)) } diff --git a/www/packages/docs-ui/src/hooks/use-tabs/index.tsx b/www/packages/docs-ui/src/hooks/use-tabs/index.tsx index 46bde579d2a2e..cdcd3d7a3bba4 100644 --- a/www/packages/docs-ui/src/hooks/use-tabs/index.tsx +++ b/www/packages/docs-ui/src/hooks/use-tabs/index.tsx @@ -30,6 +30,9 @@ export function useTabs({ tabs, group }: TabProps) { const scrollPosition = useRef(0) const changeSelectedTab = (tab: T) => { + if (tab.value === selectedTab?.value) { + return + } scrollPosition.current = window.scrollY setSelectedTab(tab) localStorage.setItem(storageKey, tab.value) diff --git a/www/packages/docs-ui/src/providers/Pagination/index.tsx b/www/packages/docs-ui/src/providers/Pagination/index.tsx index f2569df53d919..7104da3381df9 100644 --- a/www/packages/docs-ui/src/providers/Pagination/index.tsx +++ b/www/packages/docs-ui/src/providers/Pagination/index.tsx @@ -50,18 +50,23 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { const getFirstChild = ( item: SidebarItemType - ): SidebarItemType | undefined => { + ): SidebarItemWithParent | undefined => { const children = getChildrenWithPages(item) if (!children?.length) { return undefined } - return children[0].path ? children[0] : getFirstChild(children[0]) + return children[0].path + ? { + ...children[0], + parent: item, + } + : getFirstChild(children[0]) } const getChildrenWithPages = ( item: SidebarItemType - ): SidebarItemType[] | undefined => { + ): SidebarItemWithParent[] | undefined => { return item.children?.filter( (childItem) => childItem.path !== undefined || getChildrenWithPages(childItem)?.length diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/auth-provider.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/auth-provider.ts index 01b1be8b1c5ef..e8b98ffb1e400 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/auth-provider.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/auth-provider.ts @@ -39,10 +39,11 @@ Create the file \`src/modules/my-auth/index.ts\` with the following content: \`\`\`ts title="src/modules/my-auth/index.ts" import MyAuthProviderService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-auth", { service: MyAuthProviderService, -} +}) \`\`\` This exports the module's definition, indicating that the \`MyAuthProviderService\` is the main service of the module.`, @@ -51,7 +52,7 @@ This exports the module's definition, indicating that the \`MyAuthProviderServic To use your Auth Provider Module, add it to the \`providers\` array of the Auth Module: \`\`\`js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -64,12 +65,9 @@ module.exports = defineConfig({ providers: [ { resolve: "./modules/my-auth", + id: "my-auth", options: { - config: { - "my-auth": { - // provider options... - }, - }, + // provider options... }, }, ], 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 6706f0abc0e3b..541ed83f74da1 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 @@ -39,10 +39,11 @@ Create the file \`src/modules/my-file/index.ts\` with the following content: \`\`\`ts title="src/modules/my-file/index.ts" import MyFileProviderService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-file", { service: MyFileProviderService, -} +}) \`\`\` This exports the module's definition, indicating that the \`MyFileProviderService\` is the main service of the module.`, @@ -57,7 +58,7 @@ The File Module accepts one provider only. \`\`\`js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -70,12 +71,9 @@ module.exports = defineConfig({ providers: [ { resolve: "./modules/my-file", + id: "my-file", options: { - config: { - "my-file": { - // provider options... - }, - }, + // provider options... }, }, ], diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/fulfillment-provider.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/fulfillment-provider.ts index 2ea712ab40241..54b8475acef0f 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/fulfillment-provider.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/fulfillment-provider.ts @@ -39,10 +39,11 @@ Create the file \`src/modules/my-fulfillment/index.ts\` with the following conte \`\`\`ts title="src/modules/my-fulfillment/index.ts" import MyFulfillmentProviderService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-fulfillment", { service: MyFulfillmentProviderService, -} +}) \`\`\` This exports the module's definition, indicating that the \`MyFulfillmentProviderService\` is the main service of the module.`, @@ -51,7 +52,7 @@ This exports the module's definition, indicating that the \`MyFulfillmentProvide To use your Fulfillment Provider Module, add it to the \`providers\` array of the Fulfillment Module: \`\`\`js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -64,12 +65,9 @@ module.exports = defineConfig({ providers: [ { resolve: "./modules/my-fulfillment", + id: "my-fulfillment", options: { - config: { - "my-fulfillment": { - // provider options... - }, - }, + // 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 01b5fe0dd9cd6..18c35ba19bea8 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 @@ -43,10 +43,11 @@ Create the file \`src/modules/my-notification/index.ts\` with the following cont \`\`\`ts title="src/modules/my-notification/index.ts" import MyNotificationProviderService from "./service" +import { Module } from "@medusajs/utils" -export default { +export default Module("my-notification", { service: MyNotificationProviderService, -} +}) \`\`\` This exports the module's definition, indicating that the \`MyNotificationProviderService\` is the main service of the module.`, @@ -61,7 +62,7 @@ The Notification Module accepts one provider per channel. \`\`\`js title="medusa-config.js" -const { Modules } = require("@medusajs/modules-sdk") +import { Modules } from "@medusajs/utils" // ... @@ -74,13 +75,10 @@ module.exports = defineConfig({ providers: [ { resolve: "./modules/my-notification", + id: "my-notification", options: { - config: { - "my-notification": { - channels: ["email"], - // provider options... - }, - }, + channels: ["email"], + // provider options... }, }, ],