diff --git a/.github/workflows/docs-test.yml b/.github/workflows/docs-test.yml index 7f4d742a4a708..4882cefaef8a8 100644 --- a/.github/workflows/docs-test.yml +++ b/.github/workflows/docs-test.yml @@ -63,4 +63,25 @@ jobs: fail_on_error: true vale_flags: '--minAlertLevel=error' env: - GITHUB_TOKEN: ${{ github.token }} \ No newline at end of file + GITHUB_TOKEN: ${{ github.token }} + + eslint: + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + + - name: Checkout + uses: actions/checkout@v2.3.5 + with: + fetch-depth: 0 + + - name: Install dependencies + uses: ./.github/actions/cache-deps + with: + extension: eslint-docs + + - name: Run Eslint + run: yarn lint:docs \ No newline at end of file diff --git a/docs/.babelrc b/docs/.babelrc new file mode 100644 index 0000000000000..eb9156a908a13 --- /dev/null +++ b/docs/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-react" + ] +} \ No newline at end of file diff --git a/docs/.eslintignore b/docs/.eslintignore new file mode 100644 index 0000000000000..7a3c85e25d262 --- /dev/null +++ b/docs/.eslintignore @@ -0,0 +1 @@ +!docs/content \ No newline at end of file diff --git a/docs/.eslintrc.js b/docs/.eslintrc.js new file mode 100644 index 0000000000000..27a5e1fad2601 --- /dev/null +++ b/docs/.eslintrc.js @@ -0,0 +1,121 @@ +module.exports = { + root: true, + parser: "@babel/eslint-parser", + parserOptions: { + requireConfigFile: false, + ecmaFeatures: { + experimentalDecorators: true, + }, + }, + plugins: ["prettier", "markdown"], + extends: [ + "eslint:recommended", + "google", + "plugin:prettier/recommended", + "plugin:markdown/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + ], + settings: { + react: { + version: "detect" + } + }, + rules: { + "no-undef": "off", + "no-unused-expressions": "off", + "no-unused-vars": "off", + "no-unused-labels": "off", + "no-console": "off", + curly: ["error", "all"], + "new-cap": "off", + "require-jsdoc": "off", + "no-unused-expressions": "off", + "no-unused-vars": "off", + camelcase: "off", + "no-invalid-this": "off", + "max-len": [ + "error", + { + code: 75, + }, + ], + semi: ["error", "never"], + quotes: [ + "error", + "double", + { + allowTemplateLiterals: true, + }, + ], + "comma-dangle": [ + "error", + { + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + functions: "never", + }, + ], + "object-curly-spacing": ["error", "always"], + "arrow-parens": ["error", "always"], + "linebreak-style": 0, + "no-confusing-arrow": [ + "error", + { + allowParens: false, + }, + ], + "space-before-function-paren": [ + "error", + { + anonymous: "always", + named: "never", + asyncArrow: "always", + }, + ], + "space-infix-ops": "off", + "eol-last": ["error", "always"], + "react/prop-types": "off", + "react/jsx-no-undef": "off" + }, + env: { + es6: true, + node: true, + }, + ignorePatterns: [ + 'docs/content/references/**', + 'docs/content/advanced/backend/subscribers/events-list.md' + ], + overrides: [ + { + files: ["docs/content/**/*.md", "docs/content/**/*.mdx"], + processor: "markdown/markdown", + }, + { + files: [ + "docs/content/**/*.md/*.js", + "docs/content/**/*.mdx/*.js", + "docs/content/**/*.md/*.jsx", + "docs/content/**/*.mdx/*.jsx", + ], + }, + { + files: [ + "docs/content/**/*.md/*.ts", + "docs/content/**/*.mdx/*.ts", + "docs/content/**/*.md/*.tsx", + "docs/content/**/*.mdx/*.tsx", + ], + plugins: ["@typescript-eslint/eslint-plugin"], + extends: ["plugin:@typescript-eslint/recommended"], + parser: "@typescript-eslint/parser", + rules: { + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-explicit-any": "off", + }, + }, + ], +} diff --git a/docs/content/add-plugins/algolia.md b/docs/content/add-plugins/algolia.md index 366ccc5fdeb69..7efc23734c8f7 100644 --- a/docs/content/add-plugins/algolia.md +++ b/docs/content/add-plugins/algolia.md @@ -97,7 +97,7 @@ Finally, in `medusa-config.js` add the following item into the `plugins` arr ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-algolia`, options: { @@ -123,7 +123,7 @@ const plugins = [ }, }, }, -]; +] ``` The `searchableAttributes` are the attributes in a product that are searchable, and `attributesToRetrieve` are the attributes to retrieve for each product result. You’re free to make changes to these attributes as you see fit, but these are the recommended attributes. @@ -207,7 +207,7 @@ Finally, change the code in `src/lib/search-client.ts` to the following: ```jsx title=src/lib/search-client.ts import algoliasearch from "algoliasearch/lite" -const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "" // You should add this to your environment variables +const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "" const apiKey = process.env.NEXT_PUBLIC_SEARCH_API_KEY || "test_key" @@ -227,9 +227,7 @@ To make sure the Next.js storefront properly displays the products in the search ![Search pop up in the Next.js storefront](https://res.cloudinary.com/dza7lstvk/image/upload/v1668000082/Medusa%20Docs/Algolia/1f9qqK6_c0z8zi.png) ---- - -## Add to Gatsby and React-Based Storefronts +### Add to Gatsby and React-Based Storefronts This section covers adding the search UI to React-based storefronts. It uses the Gatsby storefront as an example, but you can use the same steps on any React-based framework. @@ -269,11 +267,11 @@ import { Hits, InstantSearch, SearchBox, - connectStateResults + connectStateResults, } from "react-instantsearch-dom" import React from "react" -import algoliasearch from 'algoliasearch/lite'; +import algoliasearch from "algoliasearch/lite" const searchClient = algoliasearch( process.env.GATSBY_ALGOLIA_APP_ID, @@ -281,19 +279,28 @@ const searchClient = algoliasearch( ) const Search = () => { - const Results = connectStateResults(({ searchState, searchResults, children }) => - searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? ( -
- {children} -
- ) : ( -
- ) - ); + const Results = connectStateResults( + ({ searchState, searchResults, children }) => { + return ( + searchState && searchState.query && + searchResults && searchResults.nbHits !== 0 ? + ( +
+ {children} +
+ ) : ( +
+ ) + ) + } + ) return (
- + @@ -313,7 +320,7 @@ const Hit = ({ hit }) => { ) } -export default Search; +export default Search ``` This file uses the dependencies you installed to show the search results. It also initializes Algolia using the environment variables you added. @@ -333,10 +340,12 @@ import Search from "./search" And add the `Search` component in the returned JSX before `RegionPopover`: ```jsx title=src/components/header/index.jsx -//... - - -//... +// ... +
+ + +
+// ... ``` If you run your Gatsby storefront while the Medusa server is running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store. diff --git a/docs/content/add-plugins/contentful/customize-contentful.md b/docs/content/add-plugins/contentful/customize-contentful.md index e54222ee89c33..cfcbad213b4df 100644 --- a/docs/content/add-plugins/contentful/customize-contentful.md +++ b/docs/content/add-plugins/contentful/customize-contentful.md @@ -29,32 +29,32 @@ Here’s an example of a migration created in a new file `contentful-migrations/ ```jsx title=contentful-migrations/rich-text.js #! /usr/bin/env node -require("dotenv").config(); +require("dotenv").config() -const { runMigration } = require("contentful-migration"); +const { runMigration } = require("contentful-migration") const options = { spaceId: process.env.CONTENTFUL_SPACE_ID, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, environment: process.env.CONTENTFUL_ENVIRONMENT, yes: true, -}; +} const migration = async () => { await runMigration({ ...options, migrationFunction: function (migration, context) { - //create Rich Text content model + // create Rich Text content model const richText = migration .createContentType("richText") .name("Rich Text") - .displayField("title"); + .displayField("title") - richText.createField("title").name("Title (Internal)").type("Symbol"); - richText.createField("body").name("Body").type("RichText"); + richText.createField("title").name("Title (Internal)").type("Symbol") + richText.createField("body").name("Body").type("RichText") - //edit Page content model + // edit Page content model const page = migration.editContentType("page") page.editField("contentModules").items({ @@ -67,7 +67,7 @@ const migration = async () => { ], }) - //edit Product content model + // edit Product content model const product = migration.editContentType("product") product @@ -83,11 +83,11 @@ const migration = async () => { }, ], }) - } - }); + }, + }) } -migration(); +migration() ``` This example creates a new content model Rich Text that has two fields: title and body. It also edits the Page content model to allow using Rich Text content models on the page. @@ -97,7 +97,19 @@ In addition, it edits the Product content model by adding a new field `contentMo You can also add other types of content models the `contentModules` should accept. For example, to accept `tileSection` add it to the `linkContentType` option: ```jsx -linkContentType: ["tileSection", "richText"], +product + .createField("contentModules") + .name("Content Modules") + .type("Array") + .items({ + type: "Link", + linkType: "Entry", + validations: [ + { + linkContentType: ["richText", "tileSection"], + }, + ], + }) ``` ### Run a Contentful Migration @@ -165,10 +177,10 @@ import { renderRichText } from "gatsby-source-contentful/rich-text" const RichText = ({ data }) => { return (
{data.body ? renderRichText(data.body) : ""}
@@ -194,7 +206,7 @@ Then, in the returned JSX add a new case to the switch statement: ```jsx title=src/pages/{ContentfulPage.slug}.js switch (cm.internal.type) { - //... + // ... case "ContentfulRichText": return default: diff --git a/docs/content/add-plugins/contentful/index.md b/docs/content/add-plugins/contentful/index.md index 6fdd84029afcf..1a709a91d5c30 100644 --- a/docs/content/add-plugins/contentful/index.md +++ b/docs/content/add-plugins/contentful/index.md @@ -123,14 +123,14 @@ Then, in `medusa-config.js` in the exported object, comment out or remove the SQ ```jsx title=medusa-config.js module.exports = { projectConfig: { - //... + // ... database_url: DATABASE_URL, database_type: "postgres", - //REMOVE OR COMMENT OUT THE BELOW: + // REMOVE OR COMMENT OUT THE BELOW: // database_database: "./medusa-db.sql", // database_type: "sqlite", }, -}; +} ``` ### Migrate Content Types to Contentful diff --git a/docs/content/add-plugins/klarna.md b/docs/content/add-plugins/klarna.md index 7afe2b3a9bd6f..fae6242abb5d2 100644 --- a/docs/content/add-plugins/klarna.md +++ b/docs/content/add-plugins/klarna.md @@ -55,22 +55,22 @@ Finally, in `medusa-config.js`, add the Klarna plugin to the `plugins` array wit ```jsx title=medusa-config.js const plugins = [ - //other plugins... + // other plugins... { resolve: `medusa-payment-klarnal`, options: { - backend_url: process.env.KLARNA_BACKEND_URL + backend_url: process.env.KLARNA_BACKEND_URL, url: process.env.KLARNA_URL, user: process.env.KLARNA_USER, password: process.env.KLARNA_PASSWORD, merchant_urls: { terms: process.env.KLARNA_TERMS_URL, checkout: process.env.KLARNA_CHECKOUT_URL, - confirmation: process.env.KLARNA_CONFIRMATION_URL - } - } - } -]; + confirmation: process.env.KLARNA_CONFIRMATION_URL, + }, + }, + }, +] ``` --- diff --git a/docs/content/add-plugins/mailchimp.md b/docs/content/add-plugins/mailchimp.md index eed61cf6f92cb..b1858aab23850 100644 --- a/docs/content/add-plugins/mailchimp.md +++ b/docs/content/add-plugins/mailchimp.md @@ -59,15 +59,15 @@ Open `medusa-config.js` and add the new plugin into the `plugins` array: ```js title=medusa-config.js const plugins = [ - ..., + // ..., { resolve: `medusa-plugin-mailchimp`, options: { api_key: process.env.MAILCHIMP_API_KEY, - newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID - } - } -]; + newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID, + }, + }, +] ``` --- @@ -147,35 +147,37 @@ npm install axios Then, in the component you want to add the subscription form add the following code: ```jsx -import axios from 'axios' -import { useState } from "react"; +import axios from "axios" +import { useState } from "react" export default function NewsletterForm() { const [email, setEmail] = useState("") function subscribe(e) { - e.preventDefault(); + e.preventDefault() if (!email) { - return; + return } - axios.post('http://localhost:9000/mailchimp/subscribe', { - email + axios.post("http://localhost:9000/mailchimp/subscribe", { + email, }) .then((e) => { alert("Subscribed sucessfully!") setEmail("") }) .catch((e) => { - console.error(e); - alert("An error occurred"); + console.error(e) + alert("An error occurred") }) } return (

Sign Up for our newsletter

- setEmail(e.target.value)} />
diff --git a/docs/content/add-plugins/meilisearch.md b/docs/content/add-plugins/meilisearch.md index b1f5f6c11606e..c788813a946c3 100644 --- a/docs/content/add-plugins/meilisearch.md +++ b/docs/content/add-plugins/meilisearch.md @@ -57,11 +57,12 @@ Finally, in `medusa-config.js` add the following item into the `plugins` array: ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-meilisearch`, options: { - // config object passed when creating an instance of the MeiliSearch client + // config object passed when creating an instance + // of the MeiliSearch client config: { host: process.env.MEILISEARCH_HOST, apiKey: process.env.MEILISEARCH_API_KEY, @@ -71,12 +72,18 @@ const plugins = [ products: { // MeiliSearch's setting options to be set on a particular index searchableAttributes: ["title", "description", "variant_sku"], - displayedAttributes: ["title", "description", "variant_sku", "thumbnail", "handle"], + displayedAttributes: [ + "title", + "description", + "variant_sku", + "thumbnail", + "handle", + ], }, }, }, }, -]; +] ``` You can change the `searchableAttributes` and `displayedAttributes` as you see fit. However, the attributes included are the recommended attributes. @@ -220,7 +227,7 @@ import { Hits, InstantSearch, SearchBox, - connectStateResults + connectStateResults, } from "react-instantsearch-dom" import React from "react" @@ -232,19 +239,28 @@ const searchClient = instantMeiliSearch( ) const Search = () => { - const Results = connectStateResults(({ searchState, searchResults, children }) => - searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? ( -
- {children} -
- ) : ( -
- ) - ); + const Results = connectStateResults( + ({ searchState, searchResults, children }) => { + return ( + searchState && searchState.query && + searchResults && searchResults.nbHits !== 0 ? + ( +
+ {children} +
+ ) : ( +
+ ) + ) + } + ) return (
- + @@ -264,7 +280,7 @@ const Hit = ({ hit }) => { ) } -export default Search; +export default Search ``` This file uses the dependencies you installed to show the search results. It also initializes MeiliSearch using the environment variables you added. @@ -284,10 +300,12 @@ import Search from "./search" And add the `Search` component in the returned JSX before `RegionPopover`: ```jsx title=src/components/header/index.jsx -//... - - -//... +// ... +
+ + +
+// ... ``` If you run your Gatsby storefront while the Medusa server and the MeiliSearch instance are running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store. diff --git a/docs/content/add-plugins/minio.md b/docs/content/add-plugins/minio.md index 7204fd86ca720..0a0ff531f6ad1 100644 --- a/docs/content/add-plugins/minio.md +++ b/docs/content/add-plugins/minio.md @@ -104,7 +104,9 @@ Where `` is the URL of your MinIO server, `` is the name of th Finally, configure your `medusa-config.js` to include the plugin with the required options: ```js title=medusa-config.js -{ +const plugins = [ + // ... + { resolve: `medusa-file-minio`, options: { endpoint: process.env.MINIO_ENDPOINT, @@ -112,7 +114,8 @@ Finally, configure your `medusa-config.js` to include the plugin with the requ access_key_id: process.env.MINIO_ACCESS_KEY, secret_access_key: process.env.MINIO_SECRET_KEY, }, -}, + }, +] ``` :::caution @@ -156,13 +159,16 @@ MINIO_PRIVATE_BUCKET=exports Then, add a new option to the plugin’s options in `medusa-config.js`: ```jsx title=medusa-config.js -{ +const plugins = [ + // ... + { resolve: `medusa-file-minio`, options: { - //... - private_bucket: process.env.MINIO_PRIVATE_BUCKET + // ... + private_bucket: process.env.MINIO_PRIVATE_BUCKET, }, -}, + }, +] ``` ### Use Different Secret and Access Keys @@ -181,14 +187,17 @@ Where `` and `` are the access Then, add two new options to the plugin’s options in `medusa-config.js`: ```jsx title=medusa-config.js -{ +const plugins = [ + // ... + { resolve: `medusa-file-minio`, options: { - //... + // ... private_access_key_id: process.env.MINIO_PRIVATE_ACCESS_KEY, - private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY + private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY, }, -}, + }, +] ``` --- @@ -204,13 +213,13 @@ In `next.config.js` add the following option in the exported object: ```jsx title=next.config.js const { withStoreConfig } = require("./store-config") -//... +// ... module.exports = withStoreConfig({ - //... + // ... images: { domains: [ - //... + // ... "127.0.0.1", ], }, diff --git a/docs/content/add-plugins/paypal.md b/docs/content/add-plugins/paypal.md index 15d4164c10520..3586825d6fb6e 100644 --- a/docs/content/add-plugins/paypal.md +++ b/docs/content/add-plugins/paypal.md @@ -57,17 +57,17 @@ Then, in `medusa-config.js`, add the PayPal plugin to the `plugins` array with t ```jsx title=medusa-config.js const plugins = [ - //other plugins... + // other plugins... { resolve: `medusa-payment-paypal`, options: { sandbox: process.env.PAYPAL_SANDBOX, client_id: process.env.PAYPAL_CLIENT_ID, client_secret: process.env.PAYPAL_CLIENT_SECRET, - auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID - } - } -]; + auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID, + }, + }, +] ``` That’s all you need to install PayPal on your Medusa server! @@ -158,12 +158,15 @@ npm install @paypal/react-paypal-js Next, create a new file `src/components/payment/paypal-payment/index.jsx` with the following content: ```jsx title=src/components/payment/paypal-payment/index.jsx -import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js"; -import React, { useMemo, useState } from "react"; +import { + PayPalButtons, + PayPalScriptProvider, +} from "@paypal/react-paypal-js" +import React, { useMemo, useState } from "react" import { navigate } from "gatsby" import { useCart } from "../../../hooks/use-cart" -import { useMedusa } from "../../../hooks/use-medusa"; +import { useMedusa } from "../../../hooks/use-medusa" const paypalClientId = process.env.GATSBY_PAYPAL_CLIENT_ID || "" @@ -179,7 +182,7 @@ const PaypalPayment = () => { const paypalSession = useMemo(() => { if (cart.payment_sessions) { - return cart.payment_sessions.find(s => s.provider_id === "paypal") + return cart.payment_sessions.find((s) => s.provider_id === "paypal") } return null @@ -200,10 +203,10 @@ const PaypalPayment = () => { await client.carts.updatePaymentSession(cart.id, "paypal", { data: { data: { - ...authorizationOrder - } - } - }); + ...authorizationOrder, + }, + }, + }) const order = await completeCart(cart.id) @@ -218,10 +221,12 @@ const PaypalPayment = () => { const handlePayment = (data, actions) => { actions.order.authorize().then((authorization) => { - if (authorization.status !== 'COMPLETED') { - setErrorMessage(`An error occurred, status: ${authorization.status}`); - setProcessing(false); - return; + if (authorization.status !== "COMPLETED") { + setErrorMessage( + `An error occurred, status: ${authorization.status}` + ) + setProcessing(false) + return } completeOrder(authorization) @@ -232,7 +237,7 @@ const PaypalPayment = () => { {errorMessage && ( {errorMessage} @@ -246,7 +251,7 @@ const PaypalPayment = () => { ) } -export default PaypalPayment; +export default PaypalPayment ``` Here’s briefly what this code snippet does: @@ -264,9 +269,11 @@ In `src/components/payment/index.js` you’ll find in the return statement a swi ```jsx title=src/components/payment/index.js switch (ps.provider_id) { case "stripe": - //... + // ... + break case "manual": - //... + // ... + break case "paypal": return default: @@ -303,28 +310,33 @@ Then, add the Client ID as an environment variable based on the framework you’ Next, create the file that will hold the PayPal component with the following content: ```jsx -import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js"; +import { + PayPalButtons, + PayPalScriptProvider, +} from "@paypal/react-paypal-js" import { useEffect, useState } from "react" import Medusa from "@medusajs/medusa-js" function Paypal() { - const client = new Medusa(); + const client = new Medusa() const [errorMessage, setErrorMessage] = useState(undefined) const [processing, setProcessing] = useState(false) - const cart //TODO retrieve the cart here + const cart = "..." // TODO retrieve the cart here const handlePayment = (data, actions) => { actions.order.authorize().then(async (authorization) => { - if (authorization.status !== 'COMPLETED') { - setErrorMessage(`An error occurred, status: ${authorization.status}`); - setProcessing(false); - return; + if (authorization.status !== "COMPLETED") { + setErrorMessage( + `An error occurred, status: ${authorization.status}` + ) + setProcessing(false) + return } const response = await client.carts.setPaymentSession(cart.id, { - "provider_id": "paypal" - }); + "provider_id": "paypal", + }) if (!response.cart) { setProcessing(false) @@ -334,30 +346,30 @@ function Paypal() { await client.carts.updatePaymentSession(cart.id, "paypal", { data: { data: { - ...authorization - } - } - }); + ...authorization, + }, + }, + }) - const {data} = await client.carts.complete(cart.id) + const { data } = await client.carts.complete(cart.id) if (!data || data.object !== "order") { setProcessing(false) return } - //order successful + // order successful alert("success") }) } return ( -
+
{cart !== undefined && ( , + "client-id": "", "currency": "EUR", - "intent": "authorize" + "intent": "authorize", }}> {errorMessage && ( {errorMessage} @@ -370,10 +382,10 @@ function Paypal() { )}
- ); + ) } -export default Paypal; +export default Paypal ``` Here’s briefly what this code snippet does: diff --git a/docs/content/add-plugins/s3.md b/docs/content/add-plugins/s3.md index 4873adf8b1783..943d92f606a05 100644 --- a/docs/content/add-plugins/s3.md +++ b/docs/content/add-plugins/s3.md @@ -118,7 +118,7 @@ Finally, in `medusa-config.js`, add to the `plugins` array the following new ite ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-file-s3`, options: { @@ -129,7 +129,7 @@ const plugins = [ secret_access_key: process.env.S3_SECRET_ACCESS_KEY, }, }, -]; +] ``` ### Add AWS Configurations @@ -140,7 +140,7 @@ For example, you can pass the `region`, `access_key_id` and `secret_access_key` ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-file-s3`, options: { @@ -150,10 +150,10 @@ const plugins = [ region: process.env.S3_REGION, access_key_id: process.env.S3_ACCESS_KEY_ID, secret_access_key: process.env.S3_SECRET_ACCESS_KEY, - } + }, }, }, -]; +] ``` Make sure to define `S3_REGION`, `S3_ACCESS_KEY_ID`, and `S3_SECRET_ACCESS_KEY` in your environment variables first. @@ -198,14 +198,14 @@ In `next.config.js` add the following option in the exported object: ```jsx title=next.config.js const { withStoreConfig } = require("./store-config") -//... +// ... module.exports = withStoreConfig({ - //... + // ... images: { domains: [ - //... - ".s3.amazonaws.com" + // ... + ".s3.amazonaws.com", ], }, }) diff --git a/docs/content/add-plugins/segment.md b/docs/content/add-plugins/segment.md index 67c17453c445c..ff4ed78ae651f 100644 --- a/docs/content/add-plugins/segment.md +++ b/docs/content/add-plugins/segment.md @@ -110,14 +110,14 @@ Finally, in `medusa-config.js`, add the following new item to the `plugins` arra ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-segment`, options: { write_key: process.env.SEGMENT_WRITE_KEY, - } - } -]; + }, + }, +] ``` --- @@ -155,24 +155,24 @@ For example, you can add the following subscriber to listen to the `customer.cre ```jsx title=src/subscribers/customer.ts class CustomerSubscriber { constructor({ segmentService, eventBusService }) { - this.segmentService = segmentService; + this.segmentService = segmentService - eventBusService.subscribe("customer.created", this.handleCustomer); + eventBusService.subscribe("customer.created", this.handleCustomer) } handleCustomer = async (data) => { - const customerData = data; - delete customerData['password_hash']; + const customerData = data + delete customerData["password_hash"] this.segmentService.track({ - event: 'Customer Created', + event: "Customer Created", userId: data.id, - properties: customerData + properties: customerData, }) - }; + } } -export default CustomerSubscriber; +export default CustomerSubscriber ``` You resolve the `SegmentService` using dependency injection. Then, when the `customer.created` event is triggered, you use the `track` method available in the `SegmentService` to send tracking data to Segment. diff --git a/docs/content/add-plugins/sendgrid.mdx b/docs/content/add-plugins/sendgrid.mdx index edb3495ba179c..2b985b0f7e050 100644 --- a/docs/content/add-plugins/sendgrid.mdx +++ b/docs/content/add-plugins/sendgrid.mdx @@ -3928,7 +3928,7 @@ Finally, in your `medusa-config.js` file, add the SendGrid plugin into the array ```jsx title=medusa-config.js const plugins = [ - ..., + // ..., { resolve: `medusa-plugin-sendgrid`, options: { @@ -3937,12 +3937,13 @@ const plugins = [ order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID, localization: { "de-DE": { // locale key - order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED, - } - } - } - } -]; + order_placed_template: + process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED, + }, + }, + }, + }, +] ``` The `api_key` and `from` options are required. Then, use the key of each template you create (from the [reference](#template-reference)) as the option name with the template ID as the value. diff --git a/docs/content/add-plugins/slack.md b/docs/content/add-plugins/slack.md index f9b25b058eeb7..316d57926c2d1 100644 --- a/docs/content/add-plugins/slack.md +++ b/docs/content/add-plugins/slack.md @@ -83,16 +83,16 @@ After that, open `medusa-config.js` and add the new plugin with its configuratio ```jsx title=medusa-config.js const plugins = [ - ..., + // ..., { resolve: `medusa-plugin-slack-notification`, options: { show_discount_code: false, slack_url: ``, - admin_orders_url: `http://localhost:7001/a/orders` - } - } -]; + admin_orders_url: `http://localhost:7001/a/orders`, + }, + }, +] ``` - Make sure to change `` with the Webhook URL you copied after creating the Slack app. diff --git a/docs/content/add-plugins/spaces.md b/docs/content/add-plugins/spaces.md index a2f3f09aaef86..7f31d81587039 100644 --- a/docs/content/add-plugins/spaces.md +++ b/docs/content/add-plugins/spaces.md @@ -105,7 +105,7 @@ Finally, in `medusa-config.js` add a new item to the `plugins` array: ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-file-spaces`, options: { @@ -116,7 +116,7 @@ const plugins = [ secret_access_key: process.env.SPACE_SECRET_ACCESS_KEY, }, }, -]; +] ``` :::caution @@ -158,14 +158,14 @@ In `next.config.js` add the following option in the exported object: ```jsx title=next.config.js const { withStoreConfig } = require("./store-config") -//... +// ... module.exports = withStoreConfig({ - //... + // ... images: { domains: [ - //... - "" + // ... + "", ], }, }) diff --git a/docs/content/add-plugins/strapi.md b/docs/content/add-plugins/strapi.md index b926bcf2e2091..b957616476fa2 100644 --- a/docs/content/add-plugins/strapi.md +++ b/docs/content/add-plugins/strapi.md @@ -94,10 +94,10 @@ Once the command is done executing, change to the newly created `medusa-server` module.exports = { projectConfig: { redis_url: REDIS_URL, - //... - } - //... -}; + // ... + }, + // ... +} ``` This uses the default Redis configurations. If you want to learn more about configuring Redis, [check out this documentation](../usage/configurations.md#redis). @@ -140,18 +140,18 @@ Finally, open `medusa-config.js` and add the following new item to the `plugins` ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-strapi`, options: { strapi_medusa_user: process.env.STRAPI_USER, strapi_medusa_password: process.env.STRAPI_PASSWORD, - strapi_url: process.env.STRAPI_URL, //optional - strapi_port: process.env.STRAPI_PORT, //optional - strapi_protocol: process.env.STRAPI_PROTOCOL //optional - } - } -]; + strapi_url: process.env.STRAPI_URL, // optional + strapi_port: process.env.STRAPI_PORT, // optional + strapi_protocol: process.env.STRAPI_PROTOCOL, // optional + }, + }, +] ``` --- diff --git a/docs/content/add-plugins/stripe.md b/docs/content/add-plugins/stripe.md index b8b5bd0443f36..d657377050bd4 100644 --- a/docs/content/add-plugins/stripe.md +++ b/docs/content/add-plugins/stripe.md @@ -48,7 +48,7 @@ In `medusa-config.js` add the following at the end of the `plugins` array: ```jsx title=medusa-config.js const plugins = [ - ..., + // ... { resolve: `medusa-payment-stripe`, options: { @@ -56,7 +56,7 @@ const plugins = [ webhook_secret: process.env.STRIPE_WEBHOOK_SECRET, }, }, -]; +] ``` :::note @@ -75,7 +75,7 @@ You’ll first retrieve the API key. You can find it by choosing API Keys from t Next, you need to add the key to your environment variables. In your Medusa server, create `.env` if it doesn’t already exist and add the Stripe key: -```jsx +```bash STRIPE_API_KEY=sk_... ``` @@ -95,7 +95,7 @@ Then, you can add a description. You must select at least one event to listen to After the Webhook is created, you’ll see "Signing secret" in the Webhook details. Click on "Reveal" to reveal the secret key. Copy that key and in your Medusa server add the Webhook secret environment variable: -```jsx +```bash STRIPE_WEBHOOK_SECRET=whsec_... ``` @@ -195,30 +195,30 @@ In this section, you’ll initialize Stripe without Medusa’s checkout workflow Create a container component that will hold the payment card component: ```jsx -import { useState } from 'react'; +import { useState } from "react" -import {Elements} from '@stripe/react-stripe-js'; -import Form from './Form'; -import {loadStripe} from '@stripe/stripe-js'; +import { Elements } from "@stripe/react-stripe-js" +import Form from "./Form" +import { loadStripe } from "@stripe/stripe-js" -const stripePromise = loadStripe('pk_...'); +const stripePromise = loadStripe("pk_...") export default function Container() { const [clientSecret, setClientSecret] = useState() - //TODO set clientSecret + // TODO set clientSecret return (
{clientSecret && (
)}
- ); + ) }; ``` @@ -237,15 +237,19 @@ Once the clientSecret is set, the `Elements` Stripe component will wrap a `Form` Create a new file for the `Form` component with the following content: ```jsx -import {CardElement, useElements, useStripe} from '@stripe/react-stripe-js'; +import { + CardElement, + useElements, + useStripe, +} from "@stripe/react-stripe-js" -export default function Form({clientSecret, cartId}) { - const stripe = useStripe(); - const elements = useElements(); +export default function Form({ clientSecret, cartId }) { + const stripe = useStripe() + const elements = useElements() async function handlePayment(e) { e.preventDefault() - //TODO handle payment + // TODO handle payment } return ( @@ -253,7 +257,7 @@ export default function Form({clientSecret, cartId}) { - ); + ) }; ``` @@ -267,8 +271,8 @@ You’ll now implement the workflow explained earlier. You’ll use Medusa’s J import Medusa from "@medusajs/medusa-js" export default function Container() { - const client = new Medusa(); - ... + const client = new Medusa() + // ... } ``` @@ -282,19 +286,21 @@ Then, in the place of the `//TODO` inside the `Container` element, initialize th ```jsx client.carts.createPaymentSessions(cart.id) - .then(({cart}) => { - //check if stripe is selected - const isStripeAvailable = cart.payment_sessions?.some((session) => session.provider_id === 'stripe'); + .then(({ cart }) => { + // check if stripe is selected + const isStripeAvailable = cart.payment_sessions?.some((session) => ( + session.provider_id === "stripe" + )) if (!isStripeAvailable) { - return; + return } - //select stripe payment session + // select stripe payment session client.carts.setPaymentSession(cart.id, { - provider_id: 'stripe' - }).then(({cart}) => { - setClientSecret(cart.payment_session.data.client_secret); - }); + provider_id: "stripe", + }).then(({ cart }) => { + setClientSecret(cart.payment_session.data.client_secret) + }) }) ``` @@ -314,8 +320,8 @@ As you’ll use Medusa’s client again make sure to import it and initialize it import Medusa from "@medusajs/medusa-js" export default function Form() { - const client = new Medusa(); - ... + const client = new Medusa() + // ... } ``` @@ -335,12 +341,12 @@ return stripe.confirmCardPayment(clientSecret, { line1, line2, postal_code, - } - } - } + }, + }, + }, }).then(({ error, paymentIntent }) => { - //TODO handle errors - client.carts.complete(cartId).then(resp => console.log(resp)) + // TODO handle errors + client.carts.complete(cartId).then((resp) => console.log(resp)) }) ``` diff --git a/docs/content/add-plugins/twilio-sms.md b/docs/content/add-plugins/twilio-sms.md index 8af5294e235be..368c4c48dfe47 100644 --- a/docs/content/add-plugins/twilio-sms.md +++ b/docs/content/add-plugins/twilio-sms.md @@ -52,16 +52,16 @@ Finally, add the plugin and its options in the `medusa-config.js` file to the `p ```jsx title=medusa-config.js const plugins = [ - ..., + // ... { resolve: `medusa-plugin-twilio-sms`, options: { account_sid: process.env.TWILIO_SMS_ACCOUNT_SID, auth_token: process.env.TWILIO_SMS_AUTH_TOKEN, - from_number: process.env.TWILIO_SMS_FROM_NUMBER - } - } -]; + from_number: process.env.TWILIO_SMS_FROM_NUMBER, + }, + }, +] ``` --- @@ -83,27 +83,27 @@ Create the file `src/services/sms.js` in your Medusa server with the following c ```jsx title=src/services/sms.js class SmsSubscriber { constructor({ twilioSmsService, orderService, eventBusService }) { - this.twilioSmsService_ = twilioSmsService; - this.orderService = orderService; + this.twilioSmsService_ = twilioSmsService + this.orderService = orderService - eventBusService.subscribe("order.placed", this.sendSMS); + eventBusService.subscribe("order.placed", this.sendSMS) } sendSMS = async (data) => { const order = await this.orderService.retrieve(data.id, { - relations: ['shipping_address'] - }); + relations: ["shipping_address"], + }) if (order.shipping_address.phone) { this.twilioSmsService_.sendSms({ to: order.shipping_address.phone, - body: 'We have received your order #' + data.id, + body: "We have received your order #" + data.id, }) } - }; + } } -export default SmsSubscriber; +export default SmsSubscriber ``` In the `constructor`, you resolve the `twilioSmsService` and `orderService` using dependency injection to use it later in the `sendSMS` method. diff --git a/docs/content/advanced/admin/import-prices.mdx b/docs/content/advanced/admin/import-prices.mdx index 35f0b4c7d6591..3fe74fe75c515 100644 --- a/docs/content/advanced/admin/import-prices.mdx +++ b/docs/content/advanced/admin/import-prices.mdx @@ -68,31 +68,31 @@ You can do that by sending the following request to the [Upload Files](https://d ```jsx -medusa.admin.uploads.create(file) //file is an instance of File +medusa.admin.uploads.create(file) // file is an instance of File .then(({ uploads }) => { - const key = uploads[0].key; -}); + const key = uploads[0].key +}) ``` ```jsx -const formData = new FormData(); -formData.append('files', file); //file is an instance of File +const formData = new FormData() +formData.append("files", file) // file is an instance of File fetch(`/admin/uploads`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'multipart/form-data', + "Content-Type": "multipart/form-data", }, - body: formData + body: formData, }) .then((response) => response.json()) .then(({ uploads }) => { - const key = uploads[0].key; -}); + const key = uploads[0].key +}) ``` @@ -123,16 +123,16 @@ You can do that by sending the following request to the [Create a Batch Job](htt ```jsx medusa.admin.batchJobs.create({ - type: 'price-list-import', + type: "price-list-import", context: { - fileKey: key, //obtained from previous step - price_list_id + fileKey: key, // obtained from previous step + price_list_id, }, - dry_run: true + dry_run: true, }) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -140,24 +140,24 @@ medusa.admin.batchJobs.create({ ```jsx fetch(`/admin/batch-jobs`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - type: 'price-list-import', + type: "price-list-import", context: { - fileKey: key, //obtained from previous step - price_list_id + fileKey: key, // obtained from previous step + price_list_id, }, - dry_run: true - }) + dry_run: true, + }), }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -212,8 +212,8 @@ You can retrieve all the details of the batch job, including its status and the ```jsx medusa.admin.batchJobs.retrieve(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -221,12 +221,12 @@ medusa.admin.batchJobs.retrieve(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -257,7 +257,7 @@ Here’s an example of the `result` property: "message": "5 prices will be added" } ], - "advancement_count": 0 //number of prices processed so far. Will be 0 before the import is confirmed. + "advancement_count": 0 //number of prices processed so far. }, ``` @@ -275,8 +275,8 @@ To confirm a batch job send the following request: ```jsx medusa.admin.batchJobs.confirm(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -284,13 +284,13 @@ medusa.admin.batchJobs.confirm(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}/confirm`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` diff --git a/docs/content/advanced/admin/import-products.mdx b/docs/content/advanced/admin/import-products.mdx index 68f99a04161c7..ee9074d0ca164 100644 --- a/docs/content/advanced/admin/import-products.mdx +++ b/docs/content/advanced/admin/import-products.mdx @@ -62,31 +62,31 @@ You can do that by sending the following request to the [Upload Files](https://d ```jsx -medusa.admin.uploads.create(file) //file is an instance of File +medusa.admin.uploads.create(file) // file is an instance of File .then(({ uploads }) => { - const key = uploads[0].key; -}); + const key = uploads[0].key +}) ``` ```jsx -const formData = new FormData(); -formData.append('files', file); //file is an instance of File +const formData = new FormData() +formData.append("files", file) // file is an instance of File fetch(`/admin/uploads`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'multipart/form-data', + "Content-Type": "multipart/form-data", }, - body: formData + body: formData, }) .then((response) => response.json()) .then(({ uploads }) => { - const key = uploads[0].key; -}); + const key = uploads[0].key +}) ``` @@ -117,15 +117,15 @@ You can do that by sending the following request to the [Create a Batch Job](htt ```jsx medusa.admin.batchJobs.create({ - type: 'product-import', + type: "product-import", context: { - fileKey: key //obtained from previous step + fileKey: key, // obtained from previous step }, - dry_run: true + dry_run: true, }) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -133,23 +133,23 @@ medusa.admin.batchJobs.create({ ```jsx fetch(`/admin/batch-jobs`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - type: 'product-import', + type: "product-import", context: { - fileKey: key //obtained from previous step + fileKey: key, // obtained from previous step }, - dry_run: true - }) + dry_run: true, + }), }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -200,8 +200,8 @@ You can retrieve all the details of the batch job, including its status and the ```jsx medusa.admin.batchJobs.retrieve(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -209,12 +209,12 @@ medusa.admin.batchJobs.retrieve(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -242,10 +242,10 @@ Here’s an example of the `result` property: { "key": "product-import-count", "name": "Products/variants to import", - "message": "There will be 2 products created (0 updated).\n 3 variants will be created and 0 updated" + "message": "There will be 2 products created..." } ], - "advancement_count": 0 //number of products processed so far. Will be 0 before the import is confirmed. + "advancement_count": 0 //number of products processed so far. }, ``` @@ -263,8 +263,8 @@ To confirm a batch job send the following request: ```jsx medusa.admin.batchJobs.confirm(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -272,13 +272,13 @@ medusa.admin.batchJobs.confirm(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}/confirm`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` diff --git a/docs/content/advanced/admin/manage-customers.mdx b/docs/content/advanced/admin/manage-customers.mdx index e91cf1009e8c4..3d250b8f07fd2 100644 --- a/docs/content/advanced/admin/manage-customers.mdx +++ b/docs/content/advanced/admin/manage-customers.mdx @@ -49,8 +49,8 @@ You can show a list of customers by sending a request to the [List Customers](/a ```ts medusa.admin.customers.list() .then(({ customers, limit, offset, count }) => { - console.log(customers.length); -}); + console.log(customers.length) +}) ``` @@ -58,12 +58,12 @@ medusa.admin.customers.list() ```ts fetch(`/admin/customers`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ customers, limit, offset, count }) => { - console.log(customers.length); -}); + console.log(customers.length) +}) ``` @@ -108,11 +108,11 @@ medusa.admin.customers.create({ email, password, first_name, - last_name + last_name, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -120,19 +120,19 @@ medusa.admin.customers.create({ ```ts fetch(`/admin/customers`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ email, password, first_name, - last_name - }) + last_name, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -177,11 +177,11 @@ You can edit a customer’s information by sending a request to the [Update a Cu ```ts medusa.admin.customers.update(customerId, { - first_name + first_name, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -189,16 +189,16 @@ medusa.admin.customers.update(customerId, { ```ts fetch(`/admin/customers/${customerId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - first_name - }) + first_name, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` diff --git a/docs/content/advanced/admin/manage-discounts.mdx b/docs/content/advanced/admin/manage-discounts.mdx index c533a6559ada1..c3a148e7b12dd 100644 --- a/docs/content/advanced/admin/manage-discounts.mdx +++ b/docs/content/advanced/admin/manage-discounts.mdx @@ -60,21 +60,21 @@ You can create a discount by sending a request to the [Create Discount](/api/adm ```jsx import { AllocationType, DiscountRuleType } from "@medusajs/medusa" -//... +// ... medusa.admin.discounts.create({ code, rule: { type: DiscountRuleType.FIXED, value: 10, - allocation: AllocationType.ITEM + allocation: AllocationType.ITEM, }, regions: [ - regionId - ] + regionId, + ], }) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -82,27 +82,27 @@ medusa.admin.discounts.create({ ```jsx fetch(`/admin/discounts`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ code, rule: { - type: 'fixed', + type: "fixed", value: 10, - allocation: 'item' + allocation: "item", }, regions: [ - regionId - ] - }) + regionId, + ], + }), }) .then((response) => response.json()) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -153,11 +153,11 @@ For example, you can update the discount’s description and status by sending t ```jsx medusa.admin.discounts.update(discountId, { description: "New description", - is_disabled: true + is_disabled: true, }) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -165,20 +165,20 @@ medusa.admin.discounts.update(discountId, { ```jsx fetch(`/admin/discounts/${discountId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ description: "New description", - is_disabled: true - }) + is_disabled: true, + }), }) .then((response) => response.json()) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -222,16 +222,16 @@ You can send a request to the [Create Condition](/api/admin/#tag/Discount-Condit ```jsx import { DiscountConditionOperator } from "@medusajs/medusa" -//... +// ... medusa.admin.discounts.createCondition(discount_id, { operator: DiscountConditionOperator.IN, products: [ - productId - ] + productId, + ], }) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -239,22 +239,22 @@ medusa.admin.discounts.createCondition(discount_id, { ```jsx fetch(`/admin/discounts/${discountId}/conditions`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - operator: 'in', + operator: "in", products: [ - productId - ] - }) + productId, + ], + }), }) .then((response) => response.json()) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -301,24 +301,28 @@ You can retrieve a condition and its resources by sending a request to the [Get ```jsx medusa.admin.discounts.getCondition(discountId, conditionId, { - expand: 'products' + expand: "products", }) .then(({ discount_condition }) => { - console.log(discount_condition.id, discount_condition.products); -}); + console.log(discount_condition.id, discount_condition.products) +}) ``` ```jsx -fetch(`/admin/discounts/${discountId}/conditions/${conditionId}&expand=products`, { - credentials: 'include' -}) +fetch( + `/admin/discounts/${discountId}` + + `/conditions/${conditionId}&expand=products`, + { + credentials: "include", + } +) .then((response) => response.json()) .then(({ discount_condition }) => { - console.log(discount_condition.id, discount_condition.products); -}); + console.log(discount_condition.id, discount_condition.products) +}) ``` @@ -351,35 +355,38 @@ For example, to update the products in a condition: medusa.admin.discounts.updateCondition(discountId, conditionId, { products: [ productId1, - productId2 - ] + productId2, + ], }) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` ```jsx -fetch(`/admin/discounts/${discountId}/conditions/${conditionId}`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - products: [ - productId1, - productId2 - ] - }) -}) +fetch( + `/admin/discounts/${discountId}/conditions/${conditionId}`, + { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + products: [ + productId1, + productId2, + ], + }), + } +) .then((response) => response.json()) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -416,22 +423,25 @@ You can delete a condition by sending a request to the [Delete Condition](/api/a ```jsx medusa.admin.discounts.deleteCondition(discountId, conditionId) .then(({ discount }) => { - console.log(discount); -}); + console.log(discount) +}) ``` ```jsx -fetch(`/admin/discounts/${discountId}/conditions/${conditionId}`, { - method: 'DELETE', - credentials: 'include' -}) +fetch( + `/admin/discounts/${discountId}/conditions/${conditionId}`, + { + method: "DELETE", + credentials: "include", + } +) .then((response) => response.json()) .then(({ discount }) => { - console.log(discount.id); -}); + console.log(discount.id) +}) ``` @@ -461,8 +471,8 @@ You can delete a discount by sending a request to the [Delete Discount](/api/adm ```jsx medusa.admin.discounts.delete(discount_id) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` @@ -470,13 +480,13 @@ medusa.admin.discounts.delete(discount_id) ```jsx fetch(`/admin/discounts/${discountId}`, { - method: 'DELETE', - credentials: 'include' + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` diff --git a/docs/content/advanced/admin/manage-regions.mdx b/docs/content/advanced/admin/manage-regions.mdx index a2d73bcbf8727..52def1da8ec93 100644 --- a/docs/content/advanced/admin/manage-regions.mdx +++ b/docs/content/advanced/admin/manage-regions.mdx @@ -57,9 +57,9 @@ You can retrieve regions available on your server using the [List Regions](/api/ ```tsx medusa.admin.regions.list() .then(({ regions, limit, offset, count }) => { - console.log(regions.length); - //display regions -}); + console.log(regions.length) + // display regions +}) ``` @@ -67,13 +67,13 @@ medusa.admin.regions.list() ```tsx fetch(`/admin/regions`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ regions, limit, offset, count }) => { - console.log(regions.length); - //display regions -}); + console.log(regions.length) + // display regions +}) ``` @@ -102,22 +102,22 @@ You can create a region by sending a request to the [Create a Region](/api/admin ```tsx medusa.admin.regions.create({ - name: 'Europe', - currency_code: 'eur', + name: "Europe", + currency_code: "eur", tax_rate: 0, payment_providers: [ - 'manual' + "manual", ], fulfillment_providers: [ - 'manual' + "manual", ], countries: [ - 'DK' - ] + "DK", + ], }) .then(({ region }) => { - console.log(region.id); -}); + console.log(region.id) +}) ``` @@ -125,27 +125,27 @@ medusa.admin.regions.create({ ```tsx fetch(`/admin/regions`, { - credentials: 'include', - method: 'POST', + credentials: "include", + method: "POST", body: JSON.stringify({ - name: 'Europe', - currency_code: 'eur', + name: "Europe", + currency_code: "eur", tax_rate: 0, payment_providers: [ - 'manual' + "manual", ], fulfillment_providers: [ - 'manual' + "manual", ], countries: [ - 'DK' - ] - }) + "DK", + ], + }), }) .then((response) => response.json()) .then(({ region }) => { - console.log(region.id); -}); + console.log(region.id) +}) ``` @@ -202,12 +202,12 @@ Alternatively, you can update the details of a region using the [Update a Region medusa.admin.regions.update(regionId, { countries: [ "DK", - "DE" - ] + "DE", + ], }) .then(({ region }) => { - console.log(region.id); -}); + console.log(region.id) +}) ``` @@ -215,25 +215,25 @@ medusa.admin.regions.update(regionId, { ```tsx fetch(`/admin/regions/${regionId}`, { - credentials: 'include', - method: 'POST', + credentials: "include", + method: "POST", body: JSON.stringify({ countries: [ - 'DK', - 'DE' - ] - }) + "DK", + "DE", + ], + }), }) .then((response) => response.json()) .then(({ region }) => { - console.log(region.id); -}); + console.log(region.id) +}) ``` -```tsx +```bash curl -L -X POST '/admin/regions/' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ @@ -271,17 +271,17 @@ You can add a shipping option to a region by sending a request to the [Create Sh ```tsx medusa.admin.shippingOptions.create({ - name: 'PostFake', + name: "PostFake", region_id: regionId, provider_id: "manual", data: { }, - price_type: 'flat_rate', - amount: 1000 + price_type: "flat_rate", + amount: 1000, }) .then(({ shipping_option }) => { - console.log(shipping_option.id); -}); + console.log(shipping_option.id) +}) ``` @@ -289,28 +289,28 @@ medusa.admin.shippingOptions.create({ ```tsx fetch(`/admin/shipping-options`, { - credentials: 'include', - method: 'POST', + credentials: "include", + method: "POST", body: JSON.stringify({ - name: 'PostFake', + name: "PostFake", region_id: regionId, provider_id: "manual", - price_type: 'flat_rate', + price_type: "flat_rate", data: { }, - amount: 1000 - }) + amount: 1000, + }), }) .then((response) => response.json()) .then(({ shipping_option }) => { - console.log(shipping_option.id); -}); + console.log(shipping_option.id) +}) ``` -```tsx +```bash curl -L -X POST '/admin/shipping-options' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ @@ -360,8 +360,8 @@ You can delete a region by sending a request to the [Delete a Region](/api/admin ```tsx medusa.admin.regions.delete(regionId) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` @@ -369,19 +369,19 @@ medusa.admin.regions.delete(regionId) ```tsx fetch(`/admin/regions/${regionId}`, { - credentials: 'include', - method: 'DELETE' + credentials: "include", + method: "DELETE", }) .then((response) => response.json()) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` -```tsx +```bash curl -L -X DELETE '/admin/regions/' \ -H 'Authorization: Bearer ' ``` diff --git a/docs/content/advanced/admin/order-edit.mdx b/docs/content/advanced/admin/order-edit.mdx index b99697912e66f..dfc73fe22451e 100644 --- a/docs/content/advanced/admin/order-edit.mdx +++ b/docs/content/advanced/admin/order-edit.mdx @@ -87,11 +87,11 @@ To do that, send a request to the [Create an OrderEdit](/api/admin/#tag/OrderEdi ```ts medusa.admin.orderEdits.create({ - order_id, //required + order_id, // required }) .then(({ order_edit }) => { - console.log(order_edit.id); -}); + console.log(order_edit.id) +}) ``` @@ -99,19 +99,19 @@ medusa.admin.orderEdits.create({ ```ts fetch(`/admin/order-edits`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - order_id - }) + order_id, + }), }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.id); -}); + console.log(order_edit.id) +}) ``` @@ -161,11 +161,11 @@ To add a new item to the original order, send a request to the [Add Line Item](/ ```ts medusa.admin.orderEdits.addLineItem(orderEditId, { quantity: 1, - variant_id + variant_id, }) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -173,20 +173,20 @@ medusa.admin.orderEdits.addLineItem(orderEditId, { ```ts fetch(`/admin/order-edits/${orderEditId}/items`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ quantity: 1, - variant_id - }) + variant_id, + }), }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -225,8 +225,8 @@ medusa.admin.orderEdits.updateLineItem(orderEditId, itemId, { quantity: 2, }) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -234,19 +234,19 @@ medusa.admin.orderEdits.updateLineItem(orderEditId, itemId, { ```ts fetch(`/admin/order-edits/${orderEditId}/items/${itemId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - quantity: 2 - }) + quantity: 2, + }), }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -280,8 +280,8 @@ You can remove an item from the original order by sending a request to the [Remo ```ts medusa.admin.orderEdits.removeLineItem(orderEditId, itemId) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -289,13 +289,13 @@ medusa.admin.orderEdits.removeLineItem(orderEditId, itemId) ```ts fetch(`/admin/order-edits/${orderEditId}/items/${itemId}`, { - method: 'DELETE', - credentials: 'include' + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.changes); -}); + console.log(order_edit.changes) +}) ``` @@ -327,22 +327,25 @@ To revert an item change, send a request to the [Delete Item Change](/api/admin/ ```ts medusa.admin.orderEdits.deleteItemChange(orderEditId, changeId) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` ```ts -fetch(`/admin/order-edits/${orderEditId}/changes/${changeId}`, { - method: 'DELETE', - credentials: 'include' -}) +fetch( + `/admin/order-edits/${orderEditId}/changes/${changeId}`, + { + method: "DELETE", + credentials: "include", + } +) .then((response) => response.json()) .then(({ id, object, deleted }) => { - console.log(id, object, deleted); -}); + console.log(id, object, deleted) +}) ``` @@ -378,7 +381,7 @@ To move an Order Edit into the request state, send a request to the [Request Con ```ts medusa.admin.orderEdits.requestConfirmation(orderEditId) .then(({ order_edit }) => { - console.log(order_edit.requested_at, order_edit.requested_by); + console.log(order_edit.requested_at, order_edit.requested_by) }) ``` @@ -387,12 +390,12 @@ medusa.admin.orderEdits.requestConfirmation(orderEditId) ```ts fetch(`/admin/order-edits/${orderEditId}/request`, { - method: 'POST', - credentials: 'include' + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.requested_at, order_edit.requested_by); + console.log(order_edit.requested_at, order_edit.requested_by) }) ``` @@ -445,7 +448,7 @@ To confirm an Order Edit, send a request to the [Confirm Order Edit](/api/admin/ ```ts medusa.admin.orderEdits.confirm(orderEditId) .then(({ order_edit }) => { - console.log(order_edit.confirmed_at, order_edit.confirmed_by); + console.log(order_edit.confirmed_at, order_edit.confirmed_by) }) ``` @@ -454,12 +457,12 @@ medusa.admin.orderEdits.confirm(orderEditId) ```ts fetch(`/admin/order-edits/${orderEditId}/confirm`, { - method: 'POST', - credentials: 'include' + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.confirmed_at, order_edit.confirmed_by); + console.log(order_edit.confirmed_at, order_edit.confirmed_by) }) ``` @@ -507,7 +510,7 @@ If the payment is authorized by the customer, it can be captured by sending a re ```ts medusa.admin.payments.capturePayment(paymentId) .then(({ payment }) => { - console.log(payment.captured_at); + console.log(payment.captured_at) }) ``` @@ -516,12 +519,12 @@ medusa.admin.payments.capturePayment(paymentId) ```ts fetch(`/admin/payments/${paymentId}/capture`, { - method: 'POST', - credentials: 'include' + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ payment }) => { - console.log(payment.captured_at); + console.log(payment.captured_at) }) ``` @@ -551,10 +554,10 @@ To refund the difference to the customer, send a request to the [Refund Payment] ```ts medusa.admin.payments.refundPayment(paymentId, { - amount + amount, }) .then(({ refund }) => { - console.log(refund.id); + console.log(refund.id) }) ``` @@ -563,18 +566,18 @@ medusa.admin.payments.refundPayment(paymentId, { ```ts fetch(`/admin/payments/${paymentId}/refund`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - amount - }) + amount, + }), }) .then((response) => response.json()) .then(({ refund }) => { - console.log(refund.id); + console.log(refund.id) }) ``` diff --git a/docs/content/advanced/admin/use-customergroups-api.mdx b/docs/content/advanced/admin/use-customergroups-api.mdx index e353c1a692374..346a1e0a08f41 100644 --- a/docs/content/advanced/admin/use-customergroups-api.mdx +++ b/docs/content/advanced/admin/use-customergroups-api.mdx @@ -44,11 +44,11 @@ You can create a customer group by sending a request to the Create Customer Grou ```jsx medusa.admin.customerGroups.create({ - name: 'VIP' + name: "VIP", }) .then(({ customer_group }) => { - console.log(customer_group.id); -}); + console.log(customer_group.id) +}) ``` @@ -56,19 +56,19 @@ medusa.admin.customerGroups.create({ ```jsx fetch(`/admin/customer-groups`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - name: 'VIP' - }) + name: "VIP", + }), }) .then((response) => response.json()) .then(({ customer_group }) => { console.log(customer_group.id) -}); +}) ``` @@ -100,8 +100,8 @@ You can get a list of all customer groups by sending a request to the List Custo ```jsx medusa.admin.customerGroups.list() .then(({ customer_groups, limit, offset, count }) => { - console.log(customer_groups.length); -}); + console.log(customer_groups.length) +}) ``` @@ -109,12 +109,12 @@ medusa.admin.customerGroups.list() ```jsx fetch(`/admin/customer-groups`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ customer_groups, limit, offset, count }) => { console.log(customer_groups.length) -}); +}) ``` @@ -144,8 +144,8 @@ You can retrieve a single customer group by sending a request to the Get a Custo ```jsx medusa.admin.customerGroups.retrieve(customerGroupId) .then(({ customer_group }) => { - console.log(customer_group.id); -}); + console.log(customer_group.id) +}) ``` @@ -153,12 +153,12 @@ medusa.admin.customerGroups.retrieve(customerGroupId) ```jsx fetch(`/admin/customer-groups/${customerGroupId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ customer_group }) => { console.log(customer_group.id) -}); +}) ``` @@ -186,12 +186,12 @@ You can update a customer group’s data by sending a request to the Update Cust ```jsx medusa.admin.customerGroups.update(customerGroupId, { metadata: { - is_seller: true - } + is_seller: true, + }, }) .then(({ customer_group }) => { - console.log(customer_group.id); -}); + console.log(customer_group.id) +}) ``` @@ -199,21 +199,21 @@ medusa.admin.customerGroups.update(customerGroupId, { ```jsx fetch(`/admin/customer-groups/${customerGroupId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ metadata: { - is_seller: true - } - }) + is_seller: true, + }, + }), }) .then((response) => response.json()) .then(({ customer_group }) => { console.log(customer_group.id) -}); +}) ``` @@ -247,8 +247,8 @@ You can delete a customer group by sending a request to the Delete a Customer Gr ```jsx medusa.admin.customerGroups.delete(customerGroupId) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` @@ -256,13 +256,13 @@ medusa.admin.customerGroups.delete(customerGroupId) ```jsx fetch(`/admin/customer-groups/${customerGroupId}`, { - method: 'DELETE', - credentials: 'include', + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ id, object, deleted }) => { console.log(id) -}); +}) ``` @@ -293,37 +293,40 @@ You can add a customer to a group by sending a request to the Customer Group’s medusa.admin.customerGroups.addCustomers(customerGroupId, { customer_ids: [ { - id: customerId - } - ] + id: customerId, + }, + ], }) .then(({ customer_group }) => { - console.log(customer_group.id); -}); + console.log(customer_group.id) +}) ``` ```jsx -fetch(`/admin/customer-groups/${customerGroupId}/customers/batch`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - customer_ids: [ - { - id: customerId - } - ] - }) -}) +fetch( + `/admin/customer-groups/${customerGroupId}/customers/batch`, + { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + customer_ids: [ + { + id: customerId, + }, + ], + }), + } +) .then((response) => response.json()) .then(({ customer_group }) => { console.log(customer_group.id) -}); +}) ``` @@ -357,8 +360,8 @@ You can retrieve a list of all customers in a customer group using the List Cust ```jsx medusa.admin.customerGroups.listCustomers(customerGroupId) .then(({ customers, count, offset, limit }) => { - console.log(customers.length); -}); + console.log(customers.length) +}) ``` @@ -366,12 +369,12 @@ medusa.admin.customerGroups.listCustomers(customerGroupId) ```jsx fetch(`/admin/customer-groups/${customerGroupId}/customers`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ customers, count, offset, limit }) => { console.log(customers.length) -}); +}) ``` @@ -404,37 +407,40 @@ You can remove customers from a customer group by sending a request to the Remov medusa.admin.customerGroups.removeCustomers(customer_group_id, { customer_ids: [ { - id: customer_id - } - ] + id: customer_id, + }, + ], }) .then(({ customer_group }) => { - console.log(customer_group.id); -}); + console.log(customer_group.id) +}) ``` ```jsx -fetch(`/admin/customer-groups/${customerGroupId}/customers/batch`, { - method: 'DELETE', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - customer_ids: [ - { - id: customerId - } - ] - }) -}) +fetch( + `/admin/customer-groups/${customerGroupId}/customers/batch`, + { + method: "DELETE", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + customer_ids: [ + { + id: customerId, + }, + ], + }), + } +) .then((response) => response.json()) .then(({ customer_group }) => { console.log(customer_group.id) -}); +}) ``` diff --git a/docs/content/advanced/backend/batch-jobs/create.md b/docs/content/advanced/backend/batch-jobs/create.md index 7ace8e2c91312..3cfc6d829a036 100644 --- a/docs/content/advanced/backend/batch-jobs/create.md +++ b/docs/content/advanced/backend/batch-jobs/create.md @@ -49,17 +49,20 @@ Batch job strategies must extend the abstract class `AbstractBatchJobStrategy` a Add the following content to the file you created: -```tsx title=src/strategies/publish.ts -import { AbstractBatchJobStrategy, BatchJobService } from '@medusajs/medusa' -import { EntityManager } from 'typeorm' +```ts title=src/strategies/publish.ts +import { + AbstractBatchJobStrategy, + BatchJobService, +} from "@medusajs/medusa" +import { EntityManager } from "typeorm" class PublishStrategy extends AbstractBatchJobStrategy { protected batchJobService_: BatchJobService processJob(batchJobId: string): Promise { - throw new Error('Method not implemented.') + throw new Error("Method not implemented.") } buildTemplate(): Promise { - throw new Error('Method not implemented.') + throw new Error("Method not implemented.") } protected manager_: EntityManager protected transactionManager_: EntityManager @@ -79,12 +82,12 @@ You will use the `batchType` later when you [interact with the Batch Job APIs](# Following the same example, add the following properties to the `PublishStrategy` class: -```tsx +```ts class PublishStrategy extends AbstractBatchJobStrategy { - static identifier = 'publish-products-strategy' - static batchType = 'publish-products' + static identifier = "publish-products-strategy" + static batchType = "publish-products" - //... + // ... } ``` @@ -98,10 +101,16 @@ Medusa runs this method before it creates the batch job to prepare the content o Implementing this method is optional. For example: -```tsx -async prepareBatchJobForProcessing(batchJob: CreateBatchJobInput, req: Express.Request): Promise { - //make changes to the batch job's fields... - return batchJob +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + async prepareBatchJobForProcessing( + batchJob: CreateBatchJobInput, + req: Express.Request + ): Promise { + // make changes to the batch job's fields... + return batchJob + } } ``` @@ -111,35 +120,38 @@ Medusa runs this method after it creates the batch job, but before it is confirm For example, this implementation of the `preProcessBatchJob` method calculates how many draft products it will published and adds it to the `result` attribute of the batch job: -```tsx -async preProcessBatchJob(batchJobId: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) - - const count = await this.productService_ - .withTransaction(transactionManager) - .count({ - status: ProductStatus.DRAFT - }); - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJob, { - result: { - advancement_count: 0, - count, - stat_descriptors: [ - { - key: 'product-publish-count', - name: 'Number of products to publish', - message: `${count} product(s) will be published.` - } - ] - } - }) - }) +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + async preProcessBatchJob(batchJobId: string): Promise { + return await this.atomicPhase_(async (transactionManager) => { + const batchJob = (await this.batchJobService_ + .withTransaction(transactionManager) + .retrieve(batchJobId)) + + const count = await this.productService_ + .withTransaction(transactionManager) + .count({ + status: ProductStatus.DRAFT, + }) + + await this.batchJobService_ + .withTransaction(transactionManager) + .update(batchJob, { + result: { + advancement_count: 0, + count, + stat_descriptors: [ + { + key: "product-publish-count", + name: "Number of products to publish", + message: `${count} product(s) will be published.`, + }, + ], + }, + }) + }) + } } ``` @@ -155,34 +167,37 @@ Medusa runs this method to process the batch job once it is confirmed. For example, this implementation of the `processJob` method retrieves all draft products and changes their status to published: -```tsx -async processJob(batchJobId: string): Promise { - return await this.atomicPhase_( - async (transactionManager) => { - const productServiceTx = this.productService_ - .withTransaction(transactionManager) +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + async processJob(batchJobId: string): Promise { + return await this.atomicPhase_( + async (transactionManager) => { + const productServiceTx = this.productService_ + .withTransaction(transactionManager) + + const productList = await productServiceTx + .list({ + status: [ProductStatus.DRAFT], + }) - const productList = await productServiceTx - .list({ - status: [ProductStatus.DRAFT] + productList.forEach(async (product: Product) => { + await productServiceTx + .update(product.id, { + status: ProductStatus.PUBLISHED, + }) }) - - productList.forEach(async (product: Product) => { - await productServiceTx - .update(product.id, { - status: ProductStatus.PUBLISHED + + await this.batchJobService_ + .withTransaction(transactionManager) + .update(batchJobId, { + result: { + advancement_count: productList.length, + }, }) - }) - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - advancement_count: productList.length - } - }) - } - ) + } + ) + } } ``` @@ -198,9 +213,12 @@ This method can be used in cases where you provide a template file to download, If not necessary to your use case, you can simply return an empty string: -```tsx -async buildTemplate(): Promise { - return '' +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + async buildTemplate(): Promise { + return "" + } } ``` @@ -212,9 +230,15 @@ By default, the `AbstractBatchJobStrategy` class implements this method and retu If you would like to change that behavior, you can override this method to return a different value: -```tsx -protected async shouldRetryOnProcessingError(batchJob: BatchJob, err: unknown): Promise { - return true +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + protected async shouldRetryOnProcessingError( + batchJob: BatchJob, + err: unknown + ): Promise { + return true + } } ``` @@ -226,9 +250,16 @@ You can use this method as implemented in `AbstractBatchJobStrategy` at any poin You can also override this method in your batch job strategy and change how it works: -```tsx -protected async handleProcessingError(batchJobId: string, err: unknown, result: T): Promise { - //different implementation... +```ts +class PublishStrategy extends AbstractBatchJobStrategy { + // ... + protected async handleProcessingError( + batchJobId: string, + err: unknown, + result: T + ): Promise { + // different implementation... + } } ``` @@ -273,13 +304,13 @@ For example, this creates a batch job of the type `publish-products`: ```jsx medusa.admin.batchJobs.create({ - type: 'publish-products', + type: "publish-products", context: { }, - dry_run: true + dry_run: true, }) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -287,21 +318,21 @@ medusa.admin.batchJobs.create({ ```jsx fetch(`/admin/batch-jobs`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - type: 'publish-products', + type: "publish-products", context: { }, - dry_run: true - }) + dry_run: true, + }), }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -335,8 +366,8 @@ You can retrieve the batch job afterward to get its status and view details abou ```jsx medusa.admin.batchJobs.retrieve(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -344,12 +375,12 @@ medusa.admin.batchJobs.retrieve(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status, batch_job.result); -}); + console.log(batch_job.status, batch_job.result) +}) ``` @@ -390,8 +421,8 @@ To process the batch job, send a request to [confirm the batch job](https://docs ```jsx medusa.admin.batchJobs.confirm(batchJobId) .then(( batch_job ) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` @@ -399,13 +430,13 @@ medusa.admin.batchJobs.confirm(batchJobId) ```jsx fetch(`/admin/batch-jobs/${batchJobId}/confirm`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ batch_job }) => { - console.log(batch_job.status); -}); + console.log(batch_job.status) +}) ``` diff --git a/docs/content/advanced/backend/dependency-container/index.md b/docs/content/advanced/backend/dependency-container/index.md index 04ab45f43de34..ea28a8462d9ed 100644 --- a/docs/content/advanced/backend/dependency-container/index.md +++ b/docs/content/advanced/backend/dependency-container/index.md @@ -565,7 +565,7 @@ To load resources, such as services, in endpoints, use the `req.scope.resolve` f For example: ```ts -const logger = req.scope.resolve('logger'); +const logger = req.scope.resolve("logger") ``` Please note that in endpoints some resources, such as repositories, are not available. @@ -577,13 +577,13 @@ In classes such as services, strategies, or subscribers, you can load resources For example: ```ts -import { OrderService } from '@medusajs/medusa'; +import { OrderService } from "@medusajs/medusa" class OrderSubscriber { - protected orderService: OrderService; + protected orderService: OrderService constructor({ orderService }) { - this.orderService = orderService; + this.orderService = orderService } } ``` diff --git a/docs/content/advanced/backend/endpoints/add.md b/docs/content/advanced/backend/endpoints/add.md index 5e7b55b26bfed..e0cc102b78522 100644 --- a/docs/content/advanced/backend/endpoints/add.md +++ b/docs/content/advanced/backend/endpoints/add.md @@ -62,12 +62,13 @@ Next, in the exported function, retrieve the CORS configurations of your server ```ts export default (rootDirectory) => { - //... + // ... - const { configModule } = getConfigFile(rootDirectory, "medusa-config") + const { configModule } = + getConfigFile(rootDirectory, "medusa-config") const { projectConfig } = configModule - //.... + // .... } ``` @@ -94,7 +95,7 @@ Finally, for each route you add, create an `OPTIONS` request and add `cors`  ```ts router.options("/admin/hello", cors(corsOptions)) router.get("/admin/hello", cors(corsOptions), (req, res) => { - //... + // ... }) ``` @@ -202,20 +203,24 @@ Protected routes are routes that should be accessible by logged-in customers or To make a storefront route protected, first, import the `authenticate-customer` middleware: ```ts -import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate-customer" +import + authenticate +from "@medusajs/medusa/dist/api/middlewares/authenticate-customer" ``` Then, add the middleware to your route: ```ts router.options("/store/hello", cors(corsOptions)) -router.get("/store/hello", cors(corsOptions), authenticate(), async (req, res) => { - if (req.user) { - //user is logged in - //to get customer id: req.user.customer_id +router.get("/store/hello", cors(corsOptions), authenticate(), + async (req, res) => { + if (req.user) { + // user is logged in + // to get customer id: req.user.customer_id + } + // ... } - //... -}) +) ``` Please note that the endpoint is still accessible by all users, however, you’ll be able to access the current logged-in customer if there’s any. @@ -227,21 +232,25 @@ To disallow guest customers from accessing the endpoint, you can throw an error To make an admin route protected, first, import the `authenticate` middleware: ```ts -import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate" +import + authenticate +from "@medusajs/medusa/dist/api/middlewares/authenticate" ``` Then, add the middleware to your route: ```ts router.options("/admin/products/count", cors(corsOptions)) -router.get("/admin/products/count", cors(corsOptions), authenticate(), async (req, res) => { - //access current user - const id = req.user.userId - const userService = req.scope.resolve("userService") - - const user = await userService.retrieve(id) - //... -}) +router.get("/admin/products/count", cors(corsOptions), authenticate(), + async (req, res) => { + // access current user + const id = req.user.userId + const userService = req.scope.resolve("userService") + + const user = await userService.retrieve(id) + // ... + } +) ``` Now, only authenticated users can access this endpoint. @@ -257,15 +266,17 @@ You can retrieve any registered service in your endpoint using `req.scope.resol Here’s an example of an endpoint that retrieves the count of products in your store: ```ts -router.get("/admin/products/count", cors(corsOptions), authenticate(), (req, res) => { - const productService = req.scope.resolve("productService") - - productService.count().then((count) => { - res.json({ - count, +router.get("/admin/products/count", cors(corsOptions), authenticate(), + (req, res) => { + const productService = req.scope.resolve("productService") + + productService.count().then((count) => { + res.json({ + count, + }) }) - }) -}) + } +) ``` The `productService` has a `count` method that returns a Promise. This Promise resolves to the count of the products. You return a JSON of the product count. diff --git a/docs/content/advanced/backend/entities/index.md b/docs/content/advanced/backend/entities/index.md index 3410df6523b01..c7abea1ea1d41 100644 --- a/docs/content/advanced/backend/entities/index.md +++ b/docs/content/advanced/backend/entities/index.md @@ -6,15 +6,15 @@ In this document, you’ll learn how you can create an [Entity](overview.md). To create an entity, create a TypeScript file in `src/models`. For example, here’s a `Post` entity defined in the file `src/models/post.ts`: -```tsx title=src/models/post.ts -import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm"; -import { BaseEntity} from "@medusajs/medusa"; +```ts title=src/models/post.ts +import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm" +import { BaseEntity } from "@medusajs/medusa" import { generateEntityId } from "@medusajs/medusa/dist/utils" @Entity() export class Post extends BaseEntity { - @Column({type: 'varchar'}) - title: string | null; + @Column({ type: "varchar" }) + title: string | null @BeforeInsert() private beforeInsert(): void { @@ -31,12 +31,12 @@ To generate an ID for your entity that matches the IDs generated for Medusa’s If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead: -```tsx -import { SoftDeletableEntity } from "@medusajs/medusa"; +```ts +import { SoftDeletableEntity } from "@medusajs/medusa" @Entity() export class Post extends SoftDeletableEntity { - //... + // ... } ``` @@ -52,7 +52,7 @@ You can learn more about Migrations, how to create them, and how to run them in Entities data can be easily accessed and modified using Typeorm [Repositories](https://typeorm.io/working-with-repository). To create a repository, create a file in `src/repositories`. For example, here’s a repository `PostRepository` created in `src/repositories/post.ts`: -```tsx title=src/repositories/post.ts +```ts title=src/repositories/post.ts import { EntityRepository, Repository } from "typeorm" import { Post } from "../models/post" @@ -85,24 +85,25 @@ npm run build You can access your custom entity data in the database in services or subscribers using the repository. For example, here’s a service that lists all posts: -```tsx -import { TransactionBaseService } from '@medusajs/medusa'; +```ts +import { TransactionBaseService } from "@medusajs/medusa" class PostService extends TransactionBaseService { constructor({ postRepository, manager }) { - super({ postRepository, manager }); + super({ postRepository, manager }) - this.postRepository = postRepository; - this.manager_ = manager; + this.postRepository = postRepository + this.manager_ = manager } async list() { - const postRepository = this.manager_.getCustomRepository(this.postRepository); - return await postRepository.find(); + const postRepository = this.manager_ + .getCustomRepository(this.postRepository) + return await postRepository.find() } } -export default PostService; +export default PostService ``` In the constructor, you can use dependency injection to get access to instances of services and repositories. Here, you initialize class fields `postRepository` and `manager`. The `manager` is a [Typeorm Entity Manager](https://typeorm.io/working-with-entity-manager). @@ -123,8 +124,8 @@ This same usage of repositories can be done in subscribers as well. To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method: -```tsx -await postRepository.softDelete(post.id); +```ts +await postRepository.softDelete(post.id) ``` --- diff --git a/docs/content/advanced/backend/feature-flags/toggle.md b/docs/content/advanced/backend/feature-flags/toggle.md index 9fb723f860677..69cebd2c6213e 100644 --- a/docs/content/advanced/backend/feature-flags/toggle.md +++ b/docs/content/advanced/backend/feature-flags/toggle.md @@ -51,9 +51,9 @@ For example, to enable the Tax-Inclusive Pricing beta feature, add the following ```jsx title=medusa-config.js module.exports = { featureFlags: { - tax_inclusive_pricing: true + tax_inclusive_pricing: true, }, - //... + // ... } ``` diff --git a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md index 3ca92225fd8de..ede8131a571eb 100644 --- a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md +++ b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md @@ -23,23 +23,39 @@ Creating a Notification Provider is as simple as creating a TypeScript or JavaS For example, create the file `src/services/email-sender.ts` with the following content: ```ts title=src/services/email-sender.ts -import { AbstractNotificationService } from "@medusajs/medusa"; -import { EntityManager } from "typeorm"; +import { AbstractNotificationService } from "@medusajs/medusa" +import { EntityManager } from "typeorm" class EmailSenderService extends AbstractNotificationService { - protected manager_: EntityManager; - protected transactionManager_: EntityManager; - - sendNotification(event: string, data: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record; }> { - throw new Error("Method not implemented."); + protected manager_: EntityManager + protected transactionManager_: EntityManager + + sendNotification( + event: string, + data: unknown, + attachmentGenerator: unknown + ): Promise<{ + to: string; + status: string; + data: Record; + }> { + throw new Error("Method not implemented.") } - resendNotification(notification: unknown, config: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record; }> { - throw new Error("Method not implemented."); + resendNotification( + notification: unknown, + config: unknown, + attachmentGenerator: unknown + ): Promise<{ + to: string; + status: string; + data: Record; + }> { + throw new Error("Method not implemented.") } } -export default EmailSenderService; +export default EmailSenderService ``` Where `EmailSenderService` is the name of your Notification Provider Service. @@ -63,7 +79,10 @@ The value of this property is also used later when you want to subscribe the Not For example, in the class you created in the previous code snippet you can add the following property: ```ts -static identifier = "email-sender"; +class EmailSenderService extends AbstractNotificationService { + static identifier = "email-sender" + // ... +} ``` ### constructor @@ -83,23 +102,26 @@ You can learn more about plugins and how to create them in the [Plugins](../plug Continuing on with the previous example, if you want to use the [`OrderService`](../../../references/services/classes/OrderService.md) later when sending notifications, you can inject it into the constructor: ```ts -import { AbstractNotificationService, OrderService } from "@medusajs/medusa"; +import { + AbstractNotificationService, + OrderService, +} from "@medusajs/medusa" class EmailSenderService extends AbstractNotificationService { - protected manager_: EntityManager; - protected transactionManager_: EntityManager; - static identifier = "email-sender"; - protected orderService: OrderService; + protected manager_: EntityManager + protected transactionManager_: EntityManager + static identifier = "email-sender" + protected orderService: OrderService constructor(container, options) { - super(container); - //you can access options here in case you're - //using a plugin + super(container) + // you can access options here in case you're + // using a plugin - this.orderService = container.orderService; + this.orderService = container.orderService } - //... + // ... } ``` @@ -129,23 +151,34 @@ This method must return an object containing two properties: Continuing with the previous example you can have the following implementation of the `sendNotification` method: ```ts -async sendNotification(event: string, data: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record; }> { - if (event === 'order.placed') { - //retrieve order - const order = await this.orderService.retrieve(data.id); - //TODO send email - - console.log('Notification sent'); - return { - to: order.email, - status: 'done', - data: { - //any data necessary to send the email - //for example: - subject: 'You placed a new order!', - items: order.items +class EmailSenderService extends AbstractNotificationService { + // ... + async sendNotification( + event: string, + data: any, + attachmentGenerator: unknown + ): Promise<{ + to: string; + status: string; + data: Record; + }> { + if (event === "order.placed") { + // retrieve order + const order = await this.orderService.retrieve(data.id) + // TODO send email + + console.log("Notification sent") + return { + to: order.email, + status: "done", + data: { + // any data necessary to send the email + // for example: + subject: "You placed a new order!", + items: order.items, + }, } - }; + } } } ``` @@ -180,17 +213,29 @@ Similarly to the `sendNotification` method, this method must return an object co Continuing with the previous example you can have the following implementation of the `resendNotification` method: ```ts -async resendNotification(notification: any, config: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record; }> { - //check if the receiver of the notification should be changed - const to: string = config.to ? config.to : notification.to; - - //TODO resend the notification using the same data that is saved under notification.data - - console.log('Notification resent'); - return { - to, - status: 'done', - data: notification.data //you can also make changes to the data +class EmailSenderService extends AbstractNotificationService { + // ... + async resendNotification( + notification: any, + config: any, + attachmentGenerator: unknown + ): Promise<{ + to: string; + status: string; + data: Record; + }> { + // check if the receiver of the notification should be changed + const to: string = config.to ? config.to : notification.to + + // TODO resend the notification using the same data + // that is saved under notification.data + + console.log("Notification resent") + return { + to, + status: "done", + data: notification.data, // you can also make changes to the data + } } } ``` @@ -224,11 +269,12 @@ Following the previous example, to make sure the `email-sender` Notification Pro ```ts title=src/subscribers/notification.js class NotificationSubscriber { constructor({ notificationService }) { - notificationService.subscribe('order.placed', 'email-sender'); + notificationService.subscribe("order.placed", "email-sender") } + // ... } -export default NotificationSubscriber; +export default NotificationSubscriber ``` This subscriber accesses the `notificationService` using dependency injection. The `notificationService` contains a `subscribe` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that is subscribing to that event. @@ -288,5 +334,5 @@ This request returns the same notification object as the List Notifications endp - [Events reference](../subscribers/events-list.md) - [SendGrid Plugin](../../../add-plugins/sendgrid.mdx) - [Create a Subscriber](../subscribers/create-subscriber.md) -- [Create a Service](../services/create-service.md). -- [Create a Plugin](../plugins/create.md). +- [Create a Service](../services/create-service.md) +- [Create a Plugin](../plugins/create.md) diff --git a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md index ba1af5059a2bd..da374726c3eb1 100644 --- a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md +++ b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md @@ -50,51 +50,60 @@ The first step to create a payment provider is to create a JavaScript or TypeScr For example, create the file `src/services/my-payment.ts` with the following content: + + ```ts title=src/services/my-payment.ts -import { AbstractPaymentService, Cart, Data, Payment, PaymentSession, PaymentSessionStatus, TransactionBaseService } from "@medusajs/medusa" -import { EntityManager } from "typeorm"; +import { + AbstractPaymentService, + Cart, Data, Payment, PaymentSession, + PaymentSessionStatus, TransactionBaseService, +} from "@medusajs/medusa" +import { EntityManager } from "typeorm" class MyPaymentService extends AbstractPaymentService { - protected manager_: EntityManager; - protected transactionManager_: EntityManager; + protected manager_: EntityManager + protected transactionManager_: EntityManager getPaymentData(paymentSession: PaymentSession): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } updatePaymentData(paymentSessionData: Data, data: Data): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } createPayment(cart: Cart): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } retrievePayment(paymentData: Data): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } updatePayment(paymentSessionData: Data, cart: Cart): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } - authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> { - throw new Error("Method not implemented."); + authorizePayment( + paymentSession: PaymentSession, + context: Data + ): Promise<{ data: Data; status: PaymentSessionStatus; }> { + throw new Error("Method not implemented.") } capturePayment(payment: Payment): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } refundPayment(payment: Payment, refundAmount: number): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } cancelPayment(payment: Payment): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } deletePayment(paymentSession: PaymentSession): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } getStatus(data: Data): Promise { - throw new Error("Method not implemented."); + throw new Error("Method not implemented.") } } -export default MyPaymentService; +export default MyPaymentService ``` Where `MyPaymentService` is the name of your Payment Provider service. For example, Stripe’s Payment Provider Service is called `StripeProviderService`. @@ -123,10 +132,16 @@ You can also use the constructor to initialize your integration with the third-p Additionally, if you’re creating your Payment Provider as an external plugin to be installed on any Medusa server and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter: + + ```ts -constructor({ productService }, options) { - super(); - //you can access options here +class MyPaymentService extends AbstractPaymentService { + // ... + constructor({ productService }, options) { + super() + // you can access options here + } + // ... } ``` @@ -140,15 +155,20 @@ This method must return an object that is going to be stored in the `data` field An example of a minimal implementation of `createPayment` that does not interact with any third-party providers: + + ```ts import { Cart, Data } from "@medusajs/medusa" -//... +// ... -async createPayment(cart: Cart): Promise { - return { - id: 'test-payment', - status: 'pending' - }; +class MyPaymentService extends AbstractPaymentService { + // ... + async createPayment(cart: Cart): Promise { + return { + id: "test-payment", + status: "pending", + } + } } ``` @@ -162,12 +182,17 @@ This method must return an object containing the data from the third-party provi An example of a minimal implementation of `retrievePayment` where you don’t need to interact with the third-party provider: + + ```ts import { Data } from "@medusajs/medusa" -//... +// ... -async retrievePayment(paymentData: Data): Promise { - return {}; +class MyPaymentService extends AbstractPaymentService { + // ... + async retrievePayment(paymentData: Data): Promise { + return {} + } } ``` @@ -189,12 +214,17 @@ This method returns a string that represents the status. The status must be one An example of a minimal implementation of `getStatus` where you don’t need to interact with the third-party provider: + + ```ts import { Data, PaymentSessionStatus } from "@medusajs/medusa" -//... +// ... -async getStatus(data: Data): Promise { - return PaymentSessionStatus.AUTHORIZED; +class MyPaymentService extends AbstractPaymentService { + // ... + async getStatus(data: Data): Promise { + return PaymentSessionStatus.AUTHORIZED + } } ``` @@ -222,12 +252,17 @@ This method must return an object that will be stored in the `data` field of the An example of a minimal implementation of `updatePayment` that does not need to make any updates on the third-party provider or the `data` field of the Payment Session: + + ```ts -import { Cart, Data } from "@medusajs/medusa"; -//... +import { Cart, Data } from "@medusajs/medusa" +// ... -async updatePayment(paymentSessionData: Data, cart: Cart): Promise { - return paymentSessionData; +class MyPaymentService extends AbstractPaymentService { + // ... + async updatePayment(paymentSessionData: Data, cart: Cart): Promise { + return paymentSessionData + } } ``` @@ -243,12 +278,20 @@ This method must return an object that will be stored in the `data` field of the An example of a minimal implementation of `updatePaymentData` that returns the `updatedData` passed in the body of the request as-is to update the `data` field of the Payment Session. + + ```ts -import { Data } from "@medusajs/medusa"; -//... +import { Data } from "@medusajs/medusa" +// ... -async updatePaymentData(paymentSessionData: Data, updatedData: Data): Promise { - return updatedData; +class MyPaymentService extends AbstractPaymentService { + // ... + async updatePaymentData( + paymentSessionData: Data, + updatedData: Data + ): Promise { + return updatedData + } } ``` @@ -267,12 +310,17 @@ You can use this method to interact with the third-party provider to delete data An example of a minimal implementation of `deletePayment` where no interaction with a third-party provider is required: + + ```ts -import { PaymentSession } from "@medusajs/medusa"; -//... +import { PaymentSession } from "@medusajs/medusa" +// ... -async deletePayment(paymentSession: PaymentSession): Promise { - return; +class MyPaymentService extends AbstractPaymentService { + // ... + async deletePayment(paymentSession: PaymentSession): Promise { + return + } } ``` @@ -305,17 +353,29 @@ You can utilize this method to interact with the third-party provider and perfor An example of a minimal implementation of `authorizePayment` that doesn’t need to interact with any third-party provider: + + ```ts -import { Data, PaymentSession, PaymentSessionStatus } from "@medusajs/medusa"; -//... - -async authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> { - return { - status: PaymentSessionStatus.AUTHORIZED, - data: { - id: 'test' +import { + Data, + PaymentSession, + PaymentSessionStatus, +} from "@medusajs/medusa" +// ... + +class MyPaymentService extends AbstractPaymentService { + // ... + async authorizePayment( + paymentSession: PaymentSession, + context: Data + ): Promise<{ data: Data; status: PaymentSessionStatus; }> { + return { + status: PaymentSessionStatus.AUTHORIZED, + data: { + id: "test", + }, } - }; + } } ``` @@ -329,12 +389,17 @@ This method must return an object to be stored in the `data` field of the Paymen An example of a minimal implementation of `getPaymentData`: + + ```ts -import { Data, PaymentSession } from "@medusajs/medusa"; -//... +import { Data, PaymentSession } from "@medusajs/medusa" +// ... -async getPaymentData(paymentSession: PaymentSession): Promise { - return paymentSession.data; +class MyPaymentService extends AbstractPaymentService { + // ... + async getPaymentData(paymentSession: PaymentSession): Promise { + return paymentSession.data + } } ``` @@ -352,14 +417,19 @@ This method must return an object that will be stored in the `data` field of the An example of a minimal implementation of `capturePayment` that doesn’t need to interact with a third-party provider: + + ```ts -import { Data, Payment } from "@medusajs/medusa"; -//... +import { Data, Payment } from "@medusajs/medusa" +// ... -async capturePayment(payment: Payment): Promise { - return { - status: 'captured' - }; +class MyPaymentService extends AbstractPaymentService { + // ... + async capturePayment(payment: Payment): Promise { + return { + status: "captured", + } + } } ``` @@ -377,13 +447,21 @@ This method must return an object that is stored in the `data` field of the Paym An example of a minimal implementation of `refundPayment` that doesn’t need to interact with a third-party provider: + + ```ts -import { Data, Payment } from "@medusajs/medusa"; -//... +import { Data, Payment } from "@medusajs/medusa" +// ... -async refundPayment(payment: Payment, refundAmount: number): Promise { - return { - id: 'test' +class MyPaymentService extends AbstractPaymentService { + // ... + async refundPayment( + payment: Payment, + refundAmount: number + ): Promise { + return { + id: "test", + } } } ``` @@ -405,13 +483,18 @@ This method must return an object that is stored in the `data` field of the Paym An example of a minimal implementation of `cancelPayment` that doesn’t need to interact with a third-party provider: + + ```ts -import { Data, Payment } from "@medusajs/medusa"; -//... +import { Data, Payment } from "@medusajs/medusa" +// ... -async cancelPayment(payment: Payment): Promise { - return { - id: 'test' +class MyPaymentService extends AbstractPaymentService { + // ... + async cancelPayment(payment: Payment): Promise { + return { + id: "test", + } } } ``` @@ -438,26 +521,31 @@ If you’re using Medusa’s [Next.js](../../../starters/nextjs-medusa-starter.m An example of the implementation of `retrieveSavedMethods` taken from Stripe’s Payment Provider: + + ```ts import { Customer, Data } from "@medusajs/medusa" -//... - -/** -* Fetches a customers saved payment methods if registered in Stripe. -* @param {object} customer - customer to fetch saved cards for -* @returns {Promise>} saved payments methods -*/ -async retrieveSavedMethods(customer: Customer): Promise { - if (customer.metadata && customer.metadata.stripe_id) { - const methods = await this.stripe_.paymentMethods.list({ - customer: customer.metadata.stripe_id, - type: "card", - }) - - return methods.data - } +// ... + +class MyPaymentService extends AbstractPaymentService { + // ... + /** + * Fetches a customers saved payment methods if registered in Stripe. + * @param {object} customer - customer to fetch saved cards for + * @return {Promise>} saved payments methods + */ + async retrieveSavedMethods(customer: Customer): Promise { + if (customer.metadata && customer.metadata.stripe_id) { + const methods = await this.stripe_.paymentMethods.list({ + customer: customer.metadata.stripe_id, + type: "card", + }) + + return methods.data + } - return Promise.resolve([]) + return Promise.resolve([]) + } } ``` diff --git a/docs/content/advanced/backend/plugins/create.md b/docs/content/advanced/backend/plugins/create.md index 3824f47dea75e..f2f21a28864f9 100644 --- a/docs/content/advanced/backend/plugins/create.md +++ b/docs/content/advanced/backend/plugins/create.md @@ -212,7 +212,7 @@ To pass a plugin its configurations on a Medusa server, you have to add it to th ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-custom`, options: { @@ -225,19 +225,23 @@ const plugins = [ Then, you can have access to your plugin configuration in the constructor of services in your plugin: ```jsx title=src/service/test.ts -//In a service in your plugin -constructor({}, options) { - //options contains plugin configurations - this.name = options.name + // In a service in your plugin +class MyService extends TransactionBaseService { + constructor(container, options) { + super(container) + // options contains plugin configurations + this.name = options.name + } + // ... } ``` You can also have access to the configurations in endpoints in your plugin: ```jsx title=src/api/index.ts -//in an endpoint in your plugin +// in an endpoint in your plugin export default (rootDirectory, options) => { - //options contain the plugin configurations + // options contain the plugin configurations const router = Router() router.get("/hello-world", (req, res) => { @@ -293,10 +297,10 @@ Then, add your plugin into the array of plugins in `medusa-config.js`: ```jsx title=medusa-config.js const plugins = [ - //... + // ... { resolve: `medusa-plugin-custom`, - //if your plugin has configurations + // if your plugin has configurations options: { name: "My Store", }, diff --git a/docs/content/advanced/backend/price-lists/use-api.mdx b/docs/content/advanced/backend/price-lists/use-api.mdx index 3e15111314c8a..03b190f8277c2 100644 --- a/docs/content/advanced/backend/price-lists/use-api.mdx +++ b/docs/content/advanced/backend/price-lists/use-api.mdx @@ -37,6 +37,8 @@ When you create a price list, you can specify different conditions to control wh In the body of your request, aside from the required fields, you can send the following fields to apply different conditions: + + ```js noReport { prices: [ @@ -70,28 +72,28 @@ For example, sending the following request creates a price list with two prices: import { PriceListType } from "@medusajs/medusa" medusa.admin.priceLists.create({ - name: 'New Price List', - description: 'A new price list', + name: "New Price List", + description: "A new price list", type: PriceListType.SALE, - status: 'active', + status: "active", prices: [ { amount: 1000, variant_id, - currency_code: 'eur', - max_quantity: 3 + currency_code: "eur", + max_quantity: 3, }, { amount: 1500, variant_id, - currency_code: 'eur', - min_quantity: 4 - } - ] + currency_code: "eur", + min_quantity: 4, + }, + ], }) .then(({ price_list }) => { - console.log(price_list.id); -}); + console.log(price_list.id) +}) ``` @@ -99,31 +101,31 @@ medusa.admin.priceLists.create({ ```jsx fetch(`/admin/price-lists`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - name: 'New Price List', - description: 'A new price list', - type: 'sale', - status: 'active', + name: "New Price List", + description: "A new price list", + type: "sale", + status: "active", prices: [ { amount: 1000, variant_id, - currency_code: 'eur', - max_quantity: 3 + currency_code: "eur", + max_quantity: 3, }, { amount: 1500, variant_id, - currency_code: 'eur', - min_quantity: 4 - } - ] - }) + currency_code: "eur", + min_quantity: 4, + }, + ], + }), }) .then((response) => response.json()) .then(({ price_list }) => { @@ -179,8 +181,8 @@ You can retrieve all of a price list’s details using the Get a Price List endp ```jsx medusa.admin.priceLists.retrieve(priceListId) .then(({ price_list }) => { - console.log(price_list.id); -}); + console.log(price_list.id) +}) ``` @@ -188,7 +190,7 @@ medusa.admin.priceLists.retrieve(priceListId) ```jsx fetch(`/admin/price-lists/${priceListId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ price_list }) => { @@ -199,7 +201,7 @@ fetch(`/admin/price-lists/${priceListId}`, { -```jsx +```bash curl -L -X GET '/admin/price-lists/{id}' \ -H 'Authorization: Bearer ' ``` @@ -220,11 +222,11 @@ For example, by sending the following request the end date of the price list wil ```jsx medusa.admin.priceLists.update(priceListId, { - ends_at: '2022-10-11' + ends_at: "2022-10-11", }) .then(({ price_list }) => { - console.log(price_list.id); -}); + console.log(price_list.id) +}) ``` @@ -232,14 +234,14 @@ medusa.admin.priceLists.update(priceListId, { ```jsx fetch(`/admin/price-lists/${priceListId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - ends_at: '2022-10-11' - }) + ends_at: "2022-10-11", + }), }) .then((response) => response.json()) .then(({ price_list }) => { @@ -287,13 +289,13 @@ medusa.admin.priceLists.addPrices(priceListId, { { amount: 1200, variant_id, - currency_code: 'eur' - } - ] + currency_code: "eur", + }, + ], }) .then(({ price_list }) => { - console.log(price_list.id); -}); + console.log(price_list.id) +}) ``` @@ -301,20 +303,20 @@ medusa.admin.priceLists.addPrices(priceListId, { ```jsx fetch(`/admin/price-lists/${priceListId}/prices/batch`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ prices: [ { amount: 1200, variant_id, - currency_code: 'eur' - } - ] - }) + currency_code: "eur", + }, + ], + }), }) .then((response) => response.json()) .then(({ price_list }) => { @@ -357,18 +359,23 @@ You can delete all the prices of a product’s variants using the [Delete Produc ```jsx medusa.admin.priceLists.deleteProductPrices(priceListId, productId) .then(({ ids, object, deleted }) => { - console.log(ids.length); -}); + console.log(ids.length) +}) ``` + + ```jsx -fetch(`/admin/price-lists/${priceListId}/products/${productId}/prices`, { - method: 'DELETE', - credentials: 'include', -}) +fetch( + `/admin/price-lists/${priceListId}/products/${productId}/prices`, + { + method: "DELETE", + credentials: "include", + } +) .then((response) => response.json()) .then(({ ids, object, deleted }) => { console.log(ids.length) @@ -398,18 +405,23 @@ You can delete all the prices of a variant using the [Delete Variant Prices](htt ```jsx medusa.admin.priceLists.deleteVariantPrices(priceListId, variantId) .then(({ ids, object, deleted }) => { - console.log(ids); -}); + console.log(ids) +}) ``` + + ```jsx -fetch(`/admin/price-lists/${priceListId}/variants/${variantId}/prices`, { - method: 'DELETE', - credentials: 'include', -}) +fetch( + `/admin/price-lists/${priceListId}/variants/${variantId}/prices`, + { + method: "DELETE", + credentials: "include", + } +) .then((response) => response.json()) .then(({ ids, object, deleted }) => { console.log(ids.length) @@ -419,7 +431,7 @@ fetch(`/admin/price-lists/${priceListId}/variants/${variantId}/price -```jsx +```bash curl -L -X DELETE '/admin/price-lists//variants//prices' \ -H 'Authorization: Bearer ' ``` @@ -441,8 +453,8 @@ You can delete a price list, and subsequently all prices defined in it, using th ```jsx medusa.admin.priceLists.delete(priceListId) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` @@ -450,8 +462,8 @@ medusa.admin.priceLists.delete(priceListId) ```jsx fetch(`/admin/price-lists/${priceListId}`, { - method: 'DELETE', - credentials: 'include', + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ id, object, deleted }) => { @@ -462,7 +474,7 @@ fetch(`/admin/price-lists/${priceListId}`, { -```jsx +```bash curl -L -X DELETE '/admin/price-lists/' \ -H 'Authorization: Bearer ' ``` diff --git a/docs/content/advanced/backend/sales-channels/manage-admin.mdx b/docs/content/advanced/backend/sales-channels/manage-admin.mdx index b1211b7e28dae..2cb813ee95fd0 100644 --- a/docs/content/advanced/backend/sales-channels/manage-admin.mdx +++ b/docs/content/advanced/backend/sales-channels/manage-admin.mdx @@ -57,12 +57,12 @@ You can create a sales channel by sending a request to the Create a Sales Channe ```jsx medusa.admin.salesChannels.create({ - name: 'App', - description: 'Mobile app' + name: "App", + description: "Mobile app", }) .then(({ sales_channel }) => { - console.log(sales_channel.id); -}); + console.log(sales_channel.id) +}) ``` @@ -70,20 +70,20 @@ medusa.admin.salesChannels.create({ ```jsx fetch(`/admin/sales-channels`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - name: 'App', - description: 'Mobile app' - }) + name: "App", + description: "Mobile app", + }), }) .then((response) => response.json()) .then(({ sales_channel }) => { console.log(sales_channel.id) -}); +}) ``` @@ -118,8 +118,8 @@ You can list all sales channels by sending a request to the List Sales Channels ```jsx medusa.admin.salesChannels.list() .then(({ sales_channels, limit, offset, count }) => { - console.log(sales_channels.length); -}); + console.log(sales_channels.length) +}) ``` @@ -127,12 +127,12 @@ medusa.admin.salesChannels.list() ```jsx fetch(`/admin/sales-channels`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ sales_channels, limit, offset, count }) => { console.log(sales_channels.length) -}); +}) ``` @@ -160,8 +160,8 @@ You can retrieve a sales channel’s details by its ID using the Get Sales Chann ```jsx medusa.admin.salesChannels.retrieve(salesChannelId) .then(({ sales_channel }) => { - console.log(sales_channel.id); -}); + console.log(sales_channel.id) +}) ``` @@ -169,12 +169,12 @@ medusa.admin.salesChannels.retrieve(salesChannelId) ```jsx fetch(`/admin/sales-channels/${salesChannelId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ sales_channels, limit, offset, count }) => { console.log(sales_channels.length) -}); +}) ``` @@ -201,11 +201,11 @@ You can update a Sales Channel’s details and attributes by sending a request t ```jsx medusa.admin.salesChannels.update(salesChannelId, { - is_disabled: false + is_disabled: false, }) .then(({ sales_channel }) => { - console.log(sales_channel.id); -}); + console.log(sales_channel.id) +}) ``` @@ -213,19 +213,19 @@ medusa.admin.salesChannels.update(salesChannelId, { ```jsx fetch(`/admin/sales-channels/${salesChannelId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - is_disabled: false - }) + is_disabled: false, + }), }) .then((response) => response.json()) .then(({ sales_channel }) => { console.log(sales_channel.id) -}); +}) ``` @@ -261,8 +261,8 @@ You can delete a sales channel by sending a request to the Delete Sales Channel ```jsx medusa.admin.salesChannels.delete(salesChannelId) .then(({ id, object, deleted }) => { - console.log(id); -}); + console.log(id) +}) ``` @@ -270,13 +270,13 @@ medusa.admin.salesChannels.delete(salesChannelId) ```jsx fetch(`/admin/sales-channels/${salesChannelId}`, { - method: 'DELETE', - credentials: 'include', + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ id, object, deleted }) => { console.log(id) -}); +}) ``` @@ -307,37 +307,40 @@ To add a product to a sales channel, send a request to the Sales Channel’s Add medusa.admin.salesChannels.addProducts(salesChannelId, { product_ids: [ { - id: productId - } - ] + id: productId, + }, + ], }) .then(({ sales_channel }) => { - console.log(sales_channel.id); -}); + console.log(sales_channel.id) +}) ``` ```jsx -fetch(`/admin/sales-channels/${salesChannelId}/products/batch`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - product_ids: [ - { - id: productId - } - ] - }) -}) +fetch( + `/admin/sales-channels/${salesChannelId}/products/batch`, + { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + product_ids: [ + { + id: productId, + }, + ], + }), + } +) .then((response) => response.json()) .then(({ sales_channel }) => { console.log(sales_channel.id) -}); +}) ``` @@ -373,25 +376,28 @@ You can list the products available in a sales channel by sending a request to t ```jsx medusa.admin.products.list({ sales_channel_id: [ - salesChannelId - ] + salesChannelId, + ], }) .then(({ products, limit, offset, count }) => { - console.log(products.length); -}); + console.log(products.length) +}) ``` ```jsx -fetch(`/admin/products?sales_channel_id[0]=${salesChannelId}`, { - credentials: 'include', -}) +fetch( + `/admin/products?sales_channel_id[0]=${salesChannelId}`, + { + credentials: "include", + } +) .then((response) => response.json()) .then(({ products, limit, offset, count }) => { console.log(products.length) -}); +}) ``` @@ -424,43 +430,46 @@ You can delete a product from a sales channel by sending a request to the Sales medusa.admin.salesChannels.removeProducts(salesChannelId, { product_ids: [ { - id: productId - } - ] + id: productId, + }, + ], }) .then(({ sales_channel }) => { - console.log(sales_channel.id); -}); + console.log(sales_channel.id) +}) ``` ```jsx -fetch(`/admin/sales-channels/${salesChannelId}/products/batch`, { - method: 'DELETE', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - product_ids: [ - { - id: productId - } - ] - }) -}) +fetch( + `/admin/sales-channels/${salesChannelId}/products/batch`, + { + method: "DELETE", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + product_ids: [ + { + id: productId, + }, + ], + }), + } +) .then((response) => response.json()) .then(({ sales_channel }) => { console.log(sales_channel.id) -}); +}) ``` -```jsx +```bash curl -L -X DELETE '/admin/sales-channels//products/batch' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ @@ -492,14 +501,14 @@ You can filter orders by a specific sales channel by sending a request to the Li ```jsx medusa.admin.orders.list({ sales_channel_id: [ - salesChannelId + salesChannelId, ], limit: 50, - offset: 0 + offset: 0, }) .then(({ orders, limit, offset, count }) => { - console.log(orders.length); -}); + console.log(orders.length) +}) ``` @@ -507,18 +516,18 @@ medusa.admin.orders.list({ ```jsx fetch(`/admin/orders?sales_channel_id[0]=${salesChannelId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ orders, limit, offset, count }) => { console.log(orders.length) -}); +}) ``` -```jsx +```bash curl -L -X GET '/admin/orders?sales_channel_id[0]=' \ -H 'Authorization: Bearer ' ``` diff --git a/docs/content/advanced/backend/scheduled-jobs/create.md b/docs/content/advanced/backend/scheduled-jobs/create.md index bed15584f0551..86fcf8e7e820e 100644 --- a/docs/content/advanced/backend/scheduled-jobs/create.md +++ b/docs/content/advanced/backend/scheduled-jobs/create.md @@ -38,23 +38,25 @@ To create a scheduled job, add the following code in the file you created, which ```ts title=src/loaders/publish.ts const publishJob = async (container, options) => { - const jobSchedulerService = container.resolve("jobSchedulerService"); - jobSchedulerService.create("publish-products", {}, "0 0 * * *", async () => { - //job to execute - const productService = container.resolve("productService"); - const draftProducts = await productService.list({ - status: 'draft' - }); - - for (const product of draftProducts) { - await productService.update(product.id, { - status: 'published' - }); + const jobSchedulerService = container.resolve("jobSchedulerService") + jobSchedulerService.create("publish-products", {}, "0 0 * * *", + async () => { + // job to execute + const productService = container.resolve("productService") + const draftProducts = await productService.list({ + status: "draft", + }) + + for (const product of draftProducts) { + await productService.update(product.id, { + status: "published", + }) + } } - }) + ) } -export default publishJob; +export default publishJob ``` :::info @@ -87,12 +89,12 @@ For example: ```ts jobSchedulerService.create("publish-products", { data: { - productId - } + productId, + }, }, "0 0 * * *", async (job) => { - console.log(job.data); // {productId: 'prod_124...'} - //... -}); + console.log(job.data) // {productId: 'prod_124...'} + // ... +}) ``` --- diff --git a/docs/content/advanced/backend/services/create-service.md b/docs/content/advanced/backend/services/create-service.md index 03a7d73470edb..5180c6adaa0b5 100644 --- a/docs/content/advanced/backend/services/create-service.md +++ b/docs/content/advanced/backend/services/create-service.md @@ -9,12 +9,12 @@ To create a service, create a TypeScript or JavaScript file in `src/services` to For example, if you want to create a service `helloService`, create the file `hello.ts` in `src/services` with the following content: ```ts title=/src/services/hello.ts -import { TransactionBaseService } from '@medusajs/medusa'; -import { EntityManager } from 'typeorm'; +import { TransactionBaseService } from "@medusajs/medusa" +import { EntityManager } from "typeorm" class HelloService extends TransactionBaseService { - protected manager_: EntityManager; - protected transactionManager_: EntityManager; + protected manager_: EntityManager + protected transactionManager_: EntityManager getMessage() { return `Welcome to My Store!` } @@ -32,19 +32,25 @@ As the service extends the `TransactionBaseService` class, all services in Medus So, if you want your service to use another service, simply add it as part of your constructor’s dependencies and set it to a field inside your service’s class: ```ts -private productService: ProductService; +class HelloService extends TransactionBaseService { + private productService: ProductService -constructor(container) { - super(container); - this.productService = container.productService; + constructor(container) { + super(container) + this.productService = container.productService + } + // ... } ``` Then, you can use that service anywhere in your custom service: ```ts -async getProductCount() { - return await this.productService.count(); +class HelloService extends TransactionBaseService { + // ... + async getProductCount() { + return await this.productService.count() + } } ``` @@ -69,9 +75,12 @@ npm run build To use your custom service in another custom service, you can have easy access to it in the dependencies injected to the constructor of your service: ```ts -constructor(container) { - super(container); - this.helloService = container.helloService; +class MyService extends TransactionBaseService { + constructor(container) { + super(container) + this.helloService = container.helloService + } + // ... } ``` @@ -92,8 +101,11 @@ res.json({ To use your custom service in a subscriber, you can have easy access to it in the subscriber’s dependencies injected to the constructor of your subscriber: ```ts -constructor({ helloService, eventBusService }) { - this.helloService = helloService; +class MySubscriber { + constructor({ helloService, eventBusService }) { + this.helloService = helloService + } + // ... } ``` diff --git a/docs/content/advanced/backend/shipping/add-fulfillment-provider.md b/docs/content/advanced/backend/shipping/add-fulfillment-provider.md index fadd7b0a24a5c..3d41fa456caf8 100644 --- a/docs/content/advanced/backend/shipping/add-fulfillment-provider.md +++ b/docs/content/advanced/backend/shipping/add-fulfillment-provider.md @@ -32,7 +32,7 @@ class MyFulfillmentService extends FulfillmentService { } -export default MyFulfillmentService; +export default MyFulfillmentService ``` Fulfillment provider services must extend the `FulfillmentService` class imported from `medusa-interfaces`. @@ -55,10 +55,10 @@ The value of this property will also be used to reference the fulfillment provid import { FulfillmentService } from "medusa-interfaces" class MyFulfillmentService extends FulfillmentService { - static identifier = 'my-fulfillment'; + static identifier = "my-fulfillment" } -export default MyFulfillmentService; +export default MyFulfillmentService ``` ### constructor @@ -72,9 +72,12 @@ Additionally, if you’re creating your fulfillment provider as an external plug For example: ```ts -constructor({ productService }, options) { - super(); - //you can access options here +class MyFulfillmentService extends FulfillmentService { + // ... + constructor(container, options) { + super(container) + // you can access options here + } } ``` @@ -89,15 +92,18 @@ These fulfillment options are defined in the `getFulfillmentOptions` method. Thi For example: ```ts -async getFulfillmentOptions () { - return [ - { - id: 'my-fulfillment' - }, - { - id: 'my-fulfillment-dynamic' - } - ]; +class MyFulfillmentService extends FulfillmentService { + // ... + async getFulfillmentOptions() { + return [ + { + id: "my-fulfillment", + }, + { + id: "my-fulfillment-dynamic", + }, + ] + } } ``` @@ -116,8 +122,11 @@ This method returns a boolean. If the result is false, an error is thrown and th For example, you can use this method to ensure that the `id` in the `data` object is correct: ```ts -async validateOption (data) { - return data.id == 'my-fulfillment'; +class MyFulfillmentService extends FulfillmentService { + // ... + async validateOption(data) { + return data.id == "my-fulfillment" + } } ``` @@ -144,13 +153,16 @@ If everything is valid, this method must return a value that will be stored in t For example: ```ts -async validateFulfillmentData(optionData, data, cart) { - if (data.id !== "my-fulfillment") { - throw new Error("invalid data"); - } +class MyFulfillmentService extends FulfillmentService { + // ... + async validateFulfillmentData(optionData, data, cart) { + if (data.id !== "my-fulfillment") { + throw new Error("invalid data") + } - return { - ...data + return { + ...data, + } } } ``` @@ -173,14 +185,17 @@ You can use the `data` property in the shipping method (first parameter) to acce Here is a basic implementation of `createFulfillment` for a fulfillment provider that does not interact with any third-party provider to create the fulfillment: ```ts -createFulfillment( - methodData, - fulfillmentItems, - fromOrder, - fulfillment -) { - // No data is being sent anywhere - return Promise.resolve({}) +class MyFulfillmentService extends FulfillmentService { + // ... + createFulfillment( + methodData, + fulfillmentItems, + fromOrder, + fulfillment + ) { + // No data is being sent anywhere + return Promise.resolve({}) + } } ``` @@ -206,8 +221,11 @@ This method receives as a parameter the `data` object sent with the request that For example: ```ts -canCalculate(data) { - return data.id === 'my-fulfillment-dynamic'; +class MyFulfillmentService extends FulfillmentService { + // ... + canCalculate(data) { + return data.id === "my-fulfillment-dynamic" + } } ``` @@ -224,16 +242,22 @@ This method receives three parameters: If your fulfillment provider does not provide any dynamically calculated rates you can keep the function empty: ```ts -calculatePrice() { - +class MyFulfillmentService extends FulfillmentService { + // ... + calculatePrice() { + // leave empty + } } ``` Otherwise, you can use it to calculate the price with a custom logic. For example: ```ts -calculatePrice (optionData, data, cart) { - return cart.items.length * 1000; +class MyFulfillmentService extends FulfillmentService { + // ... + calculatePrice(optionData, data, cart) { + return cart.items.length * 1000 + } } ``` @@ -250,8 +274,11 @@ It receives the return created as a parameter. The value it returns is set to th This is the basic implementation of the method for a fulfillment provider that does not contact with a third-party provider to fulfill the return: ```ts -createReturn(returnOrder) { - return Promise.resolve({}) +class MyFulfillmentService extends FulfillmentService { + // ... + createReturn(returnOrder) { + return Promise.resolve({}) + } } ``` @@ -266,8 +293,11 @@ This method receives the fulfillment being cancelled as a parameter. This is the basic implementation of the method for a fulfillment provider that does not interact with a third-party provider to cancel the fulfillment: ```ts -cancelFulfillment(fulfillment) { - return Promise.resolve({}) +class MyFulfillmentService extends FulfillmentService { + // ... + cancelFulfillment(fulfillment) { + return Promise.resolve({}) + } } ``` diff --git a/docs/content/advanced/backend/subscribers/create-subscriber.md b/docs/content/advanced/backend/subscribers/create-subscriber.md index da6172b7bbd76..75dc810e03f91 100644 --- a/docs/content/advanced/backend/subscribers/create-subscriber.md +++ b/docs/content/advanced/backend/subscribers/create-subscriber.md @@ -18,20 +18,20 @@ After creating the file under `src/subscribers`, in the constructor of your subs The `eventBusService.subscribe` method receives the name of the event as a first parameter and as a second parameter a method in your subscriber that will handle this event. -For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.js`: +For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.ts`: -```ts title=src/subscribers/orderNotifier.js +```ts title=src/subscribers/orderNotifier.ts class OrderNotifierSubscriber { constructor({ eventBusService }) { - eventBusService.subscribe("order.placed", this.handleOrder); + eventBusService.subscribe("order.placed", this.handleOrder) } handleOrder = async (data) => { console.log("New Order: " + data.id) - }; + } } -export default OrderNotifierSubscriber; +export default OrderNotifierSubscriber ``` This subscriber registers the method `handleOrder` as one of the handlers of the `order.placed` event. The method `handleOrder` will be executed every time an order is placed. It receives the order ID in the `data` parameter. You can then use the order’s details to perform any kind of task you need. @@ -51,19 +51,25 @@ You can access any service through the dependencies injected to your subscriber For example: ```ts -constructor({ productService, eventBusService }) { - this.productService = productService; +class OrderNotifierSubscriber { + constructor({ productService, eventBusService }) { + this.productService = productService - eventBusService.subscribe("order.placed", this.handleOrder); + eventBusService.subscribe("order.placed", this.handleOrder) + } + // ... } ``` You can then use `this.productService` anywhere in your subscriber’s methods. For example: ```ts -handleOrder = async (data) => { - //... - const product = this.productService.list() +class OrderNotifierSubscriber { + // ... + handleOrder = async (data) => { + // ... + const product = this.productService.list() + } } ``` diff --git a/docs/content/advanced/backend/subscribers/events-list.md b/docs/content/advanced/backend/subscribers/events-list.md index 68b8e26e27814..ee1144a7ef115 100644 --- a/docs/content/advanced/backend/subscribers/events-list.md +++ b/docs/content/advanced/backend/subscribers/events-list.md @@ -51,7 +51,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -72,7 +72,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -93,7 +93,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -116,7 +116,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -139,7 +139,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -160,7 +160,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -181,7 +181,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -202,7 +202,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of batch job + id // string ID of batch job } ``` @@ -262,7 +262,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of cart + id // string ID of cart } ``` @@ -329,8 +329,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + no_notification // boolean indicating whether a notification should be sent } ``` @@ -354,8 +354,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + no_notification // boolean indicating whether a notification should be sent } ``` @@ -379,8 +379,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + no_notification // boolean indicating whether a notification should be sent } ``` @@ -404,9 +404,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - fulfillment_id, //string ID of the fulfillment created - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + fulfillment_id, // string ID of the fulfillment created + no_notification // boolean indicating whether a notification should be sent } ``` @@ -430,9 +430,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - fulfillment_id, //string ID of the fulfillment created - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + fulfillment_id, // string ID of the fulfillment created + no_notification // boolean indicating whether a notification should be sent } ``` @@ -456,8 +456,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of claim - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of claim + no_notification // boolean indicating whether a notification should be sent } ``` @@ -505,7 +505,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of claim item + id // string ID of claim item } ``` @@ -529,7 +529,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of claim item + id // string ID of claim item } ``` @@ -553,7 +553,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of claim item + id // string ID of claim item } ``` @@ -601,7 +601,7 @@ Object of the following format: ```js noReport noCopy { - code //string 3 character ISO code of the updated currency. + code // string 3 character ISO code of the updated currency. } ``` @@ -685,11 +685,11 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of customer - email, //string email of the customer - first_name, //string first name of the customer - last_name, //string last name of the customer - token //string reset password token + id, // string ID of customer + email, // string email of the customer + first_name, // string first name of the customer + last_name, // string last name of the customer + token // string reset password token } ``` @@ -737,7 +737,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of draft order + id // string ID of draft order } ``` @@ -761,7 +761,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of draft order + id // string ID of draft order } ``` @@ -858,9 +858,9 @@ Object of the following format: ```js noReport noCopy { - id //string ID of invite - token, //string token generated to validate the invited user - user_email //string email of invited user + id // string ID of invite + token, // string token generated to validate the invited user + user_email // string email of invited user } ``` @@ -907,7 +907,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of note + id // string ID of note } ``` @@ -931,7 +931,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of note + id // string ID of note } ``` @@ -955,7 +955,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of note + id // string ID of note } ``` @@ -1070,8 +1070,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1095,8 +1095,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - no_notification //(optional) boolean indicating whether a notification should be sent or not + id, // string ID of order + no_notification // (optional) boolean indicating whether a notification should be sent } ``` @@ -1120,8 +1120,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1145,8 +1145,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1194,7 +1194,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of order + id // string ID of order } ``` @@ -1218,8 +1218,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1243,10 +1243,10 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - payment_id, //string ID of Payment - error, //string error message - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + payment_id, // string ID of Payment + error, // string error message + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1270,9 +1270,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - fulfillment_id, //string ID of fulfillment - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + fulfillment_id, // string ID of fulfillment + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1296,9 +1296,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - fulfillment_id, //string ID of fulfillment - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + fulfillment_id, // string ID of fulfillment + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1322,9 +1322,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - fulfillment_id, //string ID of fulfillment - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + fulfillment_id, // string ID of fulfillment + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1348,9 +1348,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - return_id, //string ID of return - no_notification //(optional) boolean indicating whether a notification should be sent or not + id, // string ID of order + return_id, // string ID of return + no_notification // (optional) boolean indicating whether a notification should be sent } ``` @@ -1374,9 +1374,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - return_id, //string ID of return - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + return_id, // string ID of return + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1400,9 +1400,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - return_id, //string ID of return - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + return_id, // string ID of return + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1426,9 +1426,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of order - refund_id, //string ID of refund - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of order + refund_id, // string ID of refund + no_notification // boolean indicating whether a notification should be sent } ``` @@ -1631,7 +1631,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of order edit + id // string ID of order edit } ``` @@ -1712,7 +1712,7 @@ Triggered when an order edit item change is created. ```js noReport noCopy { - id //string ID of item change + id // string ID of item change } ``` @@ -1734,7 +1734,7 @@ Triggered when an order edit item change is deleted. ```js noReport noCopy { - id //string ID of item change + id // string ID of item change } ``` @@ -2027,7 +2027,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of product + id // string ID of product } ``` @@ -2053,8 +2053,8 @@ In one case, when the `/admin/products/{id}` endpoint is used to update the prod ```js noReport noCopy { - id, //id of product - fields //an array of field names that were updated + id, // id of product + fields // an array of field names that were updated } ``` @@ -2078,7 +2078,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of product + id // string ID of product } ``` @@ -2126,8 +2126,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of variant - product_id //string ID of product + id, // string ID of variant + product_id // string ID of product } ``` @@ -2151,9 +2151,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of variant - product_id, //string ID of product - fields //array of names of updated fields + id, // string ID of variant + product_id, // string ID of product + fields // array of names of updated fields } ``` @@ -2177,9 +2177,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of variant - product_id, //string ID of product - metadata //object of the `metadata` field of the variant + id, // string ID of variant + product_id, // string ID of product + metadata // object of the `metadata` field of the variant } ``` @@ -2239,7 +2239,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of publishable API key + id // string ID of publishable API key } ``` @@ -2263,7 +2263,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of publishable API key + id // string ID of publishable API key } ``` @@ -2311,7 +2311,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of region + id // string ID of region } ``` @@ -2335,8 +2335,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of region - fields //array of names of updated fields + id, // string ID of region + fields // array of names of updated fields } ``` @@ -2360,7 +2360,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of region + id // string ID of region } ``` @@ -2418,7 +2418,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of sales channel + id // string ID of sales channel } ``` @@ -2466,7 +2466,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of sales channel + id // string ID of sales channel } ``` @@ -2513,8 +2513,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2538,9 +2538,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - order_id, //string ID of order - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + order_id, // string ID of order + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2564,9 +2564,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - fulfillment_id, //string ID of fulfillment - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + fulfillment_id, // string ID of fulfillment + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2590,9 +2590,9 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - fulfillment_id, //string ID of fulfillment - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + fulfillment_id, // string ID of fulfillment + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2616,8 +2616,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2641,8 +2641,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2666,8 +2666,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2691,8 +2691,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2716,8 +2716,8 @@ Object of the following format: ```js noReport noCopy { - id, //string ID of swap - no_notification //boolean indicating whether a notification should be sent or not + id, // string ID of swap + no_notification // boolean indicating whether a notification should be sent } ``` @@ -2816,7 +2816,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of user + id // string ID of user } ``` @@ -2840,7 +2840,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of user + id // string ID of user } ``` @@ -2864,8 +2864,8 @@ Object of the following format: ```js noReport noCopy { - email, //string email of user requesting to reset their password - token //token create to reset the password + email, // string email of user requesting to reset their password + token // token create to reset the password } ``` @@ -2889,7 +2889,7 @@ Object of the following format: ```js noReport noCopy { - id //string ID of user + id // string ID of user } ``` diff --git a/docs/content/advanced/backend/taxes/inclusive-pricing.md b/docs/content/advanced/backend/taxes/inclusive-pricing.md index ca2c036c65913..a106fea87b5da 100644 --- a/docs/content/advanced/backend/taxes/inclusive-pricing.md +++ b/docs/content/advanced/backend/taxes/inclusive-pricing.md @@ -126,7 +126,9 @@ Where `amount` is the amount of the variant’s price in the price list, `taxRat Here is an example of these fields when tax inclusivity is enabled for both the currency and the price list: -```jsx noReport + + +```js noReport { original_price: 110, calculated_price: 100, diff --git a/docs/content/advanced/backend/taxes/manual-calculation.md b/docs/content/advanced/backend/taxes/manual-calculation.md index 63a6302d88e54..a73d5e6712b5a 100644 --- a/docs/content/advanced/backend/taxes/manual-calculation.md +++ b/docs/content/advanced/backend/taxes/manual-calculation.md @@ -29,7 +29,7 @@ You can, however, force calculating the taxes of the cart by passing in the thir For example: ```jsx -cartService.retrieve('cart_01G8Z...', { }, { force_taxes: true }); +cartService.retrieve("cart_01G8Z...", { }, { force_taxes: true }) ``` :::tip @@ -45,20 +45,20 @@ Another way you can use the `CartService` to calculate taxes is using the method ```jsx export default () => { - //... + // ... router.get("/store/line-taxes", async (req, res) => { - //example of retrieving cart - const cartService = req.scope.resolve("cartService"); + // example of retrieving cart + const cartService = req.scope.resolve("cartService") const cart = await cartService.retrieve(cart_id) - //... - //retrieve taxes of line items + // ... + // retrieve taxes of line items const data = await decorateTotals(cart, { - force_taxes: true + force_taxes: true, }) - return res.status(200).json({ cart: data }); + return res.status(200).json({ cart: data }) }) } ``` @@ -72,7 +72,7 @@ You can calculate and retrieve taxes of line items using the `getLineItemTotals` ```jsx const itemTotals = await totalsService .getLineItemTotals(item, cart, { - include_tax: true + include_tax: true, }) ``` diff --git a/docs/content/advanced/backend/upgrade-guides/1-3-0.md b/docs/content/advanced/backend/upgrade-guides/1-3-0.md index 14001b73c93f0..62768e48e80e6 100644 --- a/docs/content/advanced/backend/upgrade-guides/1-3-0.md +++ b/docs/content/advanced/backend/upgrade-guides/1-3-0.md @@ -35,28 +35,29 @@ If you use a `.env` file to load environment variables on your server, you need You can add the following code snippet at the top of the file which uses the [dotenv](https://www.npmjs.com/package/dotenv) package to load the environment variables based on the current Node environment: ```jsx -const dotenv = require('dotenv') +const dotenv = require("dotenv") - let ENV_FILE_NAME = ''; + let ENV_FILE_NAME = "" switch (process.env.NODE_ENV) { - case 'production': - ENV_FILE_NAME = '.env.production'; - break; - case 'staging': - ENV_FILE_NAME = '.env.staging'; - break; - case 'test': - ENV_FILE_NAME = '.env.test'; - break; - case 'development': + case "production": + ENV_FILE_NAME = ".env.production" + break + case "staging": + ENV_FILE_NAME = ".env.staging" + break + case "test": + ENV_FILE_NAME = ".env.test" + break + case "development": default: - ENV_FILE_NAME = '.env'; - break; + ENV_FILE_NAME = ".env" + break } try { - dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME }); + dotenv.config({ path: process.cwd() + "/" + ENV_FILE_NAME }) } catch (e) { + // handle error } ``` diff --git a/docs/content/advanced/backend/upgrade-guides/1-7-0.md b/docs/content/advanced/backend/upgrade-guides/1-7-0.md index a13bed0c79f87..d6ef8caa9daa6 100644 --- a/docs/content/advanced/backend/upgrade-guides/1-7-0.md +++ b/docs/content/advanced/backend/upgrade-guides/1-7-0.md @@ -31,19 +31,19 @@ Instead of using `customerService.retrieveByEmail`, you should now use the metho The `customerService.retrieveRegisteredByEmail` method allows you to retrieve a registered customer by email: ```ts -customerService.retrieveRegisteredByEmail("example@gmail.com"); +customerService.retrieveRegisteredByEmail("example@gmail.com") ``` On the other hand, the `retrieveUnregisteredByEmail` method allows to retrieve guest customers by email: ```jsx -customerService.retrieveUnregisteredByEmail("example@gmail.com"); +customerService.retrieveUnregisteredByEmail("example@gmail.com") ``` To retrieve a customer by email regardless of whether they are registered or not, you can use the `customerService.list` method instead: ```ts customerService.list({ - email: "example@gmail.com" + email: "example@gmail.com", }) ``` diff --git a/docs/content/advanced/backend/upgrade-guides/1-7-1.md b/docs/content/advanced/backend/upgrade-guides/1-7-1.md index fe370bb730e7d..1a1f2d617cb0a 100644 --- a/docs/content/advanced/backend/upgrade-guides/1-7-1.md +++ b/docs/content/advanced/backend/upgrade-guides/1-7-1.md @@ -56,13 +56,13 @@ In your loader file that creates a cron job, replace the use of `eventBus` to `j ```ts const myJob = async (container, options) => { - const jobSchedulerService = container.resolve("jobSchedulerService"); + const jobSchedulerService = container.resolve("jobSchedulerService") jobSchedulerService.create("my-job", {}, "0 0 * * *", async () => { - //... - }); + // ... + }) } -export default myJob; +export default myJob ``` You can learn more in the [How to Create a Scheduled Job](../scheduled-jobs/create.md) documentation. @@ -73,15 +73,26 @@ This version of Medusa introduces a change in how payment providers are implemen Although this change is currently backwards compatible, it is recommended to change the signature of these methods to the following: -```ts -import { PaymentContext, PaymentSessionResponse } from '@medusajs/medusa' + -async createPayment(context: PaymentContext): Promise { - //... -} +```ts +import { PaymentContext, PaymentSessionResponse } from "@medusajs/medusa" +// ... + +class MyPaymentService extends AbstractPaymentService { + // ... + async createPayment( + context: PaymentContext + ): Promise { + // ... + } -async updatePayment(paymentSessionData: PaymentSessionData, context: PaymentContext): Promise { - //... + async updatePayment( + paymentSessionData: PaymentSessionData, + context: PaymentContext + ): Promise { + // ... + } } ``` diff --git a/docs/content/advanced/ecommerce/handle-order-claim-event.md b/docs/content/advanced/ecommerce/handle-order-claim-event.md index 09661d7de0a85..2b394871ba78b 100644 --- a/docs/content/advanced/ecommerce/handle-order-claim-event.md +++ b/docs/content/advanced/ecommerce/handle-order-claim-event.md @@ -47,7 +47,7 @@ You can learn more about subscribers in the [Subscribers](../backend/subscribers Create the file `src/subscribers/claim-order.ts` with the following content: ```ts title=src/subscribers/claim-order.ts -import { EventBusService } from "@medusajs/medusa"; +import { EventBusService } from "@medusajs/medusa" type InjectedDependencies = { eventBusService: EventBusService, @@ -59,7 +59,7 @@ class ClaimOrderSubscriber { } } -export default ClaimOrderSubscriber; +export default ClaimOrderSubscriber ``` If you want to add any other dependencies, you can add them to the `InjectedDependencies` type. @@ -77,8 +77,14 @@ You can learn more about dependency injection in [this documentation](../backend In the subscriber you created, add the following in the `constructor`: ```ts title=src/subscribers/claim-order.ts -constructor({ eventBusService }: InjectedDependencies) { - eventBusService.subscribe("order-update-token.created", this.handleRequestClaimOrder); +class ClaimOrderSubscriber { + constructor({ eventBusService }: InjectedDependencies) { + eventBusService.subscribe( + "order-update-token.created", + this.handleRequestClaimOrder + ) + } + // ... } ``` @@ -90,14 +96,14 @@ In the subscriber, add a new method `handleRequestClaimOrder`: ```ts title=src/subscribers/claim-order.ts class ClaimOrderSubscriber { - //... + // ... - handleRequestClaimOrder = async (data) { - //TODO: handle event + handleRequestClaimOrder = async (data) => { + // TODO: handle event } } -export default ClaimOrderSubscriber; +export default ClaimOrderSubscriber ``` The `handleRequestClaimOrder` event receives a `data` object as a parameter. This object holds the following properties: @@ -118,7 +124,7 @@ The page would then send a request to the server to verify that the `token` is v For example, you can implement this subscriber to send emails using SendGrid: ```ts title=src/subscribers/claim-order.ts -import { EventBusService } from "@medusajs/medusa"; +import { EventBusService } from "@medusajs/medusa" type InjectedDependencies = { eventBusService: EventBusService, @@ -126,28 +132,31 @@ type InjectedDependencies = { } class ClaimOrderSubscriber { - protected sendGridService: any; + protected sendGridService: any constructor({ eventBusService, sendgridService }: InjectedDependencies) { - this.sendGridService = sendgridService; - eventBusService.subscribe("order-update-token.created", this.handleRequestClaimOrder); + this.sendGridService = sendgridService + eventBusService.subscribe( + "order-update-token.created", + this.handleRequestClaimOrder + ) } handleRequestClaimOrder = async (data) => { this.sendGridService.sendEmail({ - templateId: 'order-claim-confirmation', - from: 'hello@medusajs.com', + templateId: "order-claim-confirmation", + from: "hello@medusajs.com", to: data.old_email, data: { - link: `http://example-storefront.com/confirm-order-claim/${data.token}`, - //other data... - } + link: `http://example.com/confirm-order-claim/${data.token}`, + // other data... + }, }) } } -export default ClaimOrderSubscriber; +export default ClaimOrderSubscriber ``` Notice how the `token` is passed to the storefront link as a parameter. diff --git a/docs/content/advanced/storefront/customer-profiles.mdx b/docs/content/advanced/storefront/customer-profiles.mdx index 8a1f5435d0c75..d950a13b8d945 100644 --- a/docs/content/advanced/storefront/customer-profiles.mdx +++ b/docs/content/advanced/storefront/customer-profiles.mdx @@ -60,8 +60,8 @@ medusa.customers.create({ last_name, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -69,19 +69,19 @@ medusa.customers.create({ ```ts fetch(`/store/customers`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ email, password, first_name, last_name, - }) + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -112,11 +112,11 @@ You can log in a customer into your store by sending a request to the [Customer ```ts medusa.auth.authenticate({ email, - password + password, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -124,17 +124,17 @@ medusa.auth.authenticate({ ```ts fetch(`/store/auth`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ email, - password - }) + password, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -158,8 +158,8 @@ You can log out a customer by sending a request to the [Customer Logout](/api/st ```ts medusa.auth.deleteSession() .then(() => { - //success -}); + // success +}) ``` @@ -167,12 +167,12 @@ medusa.auth.deleteSession() ```ts fetch(`/store/auth`, { - method: 'DELETE', - credentials: 'include' + method: "DELETE", + credentials: "include", }) .then(() => { - //success -}); + // success +}) ``` @@ -197,7 +197,7 @@ You can request to reset a customer’s password by sending a request to the [Re ```ts medusa.customers.generatePasswordToken({ - email + email, }) .then(() => { // successful @@ -212,11 +212,11 @@ medusa.customers.generatePasswordToken({ ```ts fetch(`/store/customers/password-token`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - email - }) + email, + }), }) .then(() => { // successful @@ -252,11 +252,11 @@ You can then reset the customer’s password to the new password they enter by s medusa.customers.resetPassword({ email, password, - token + token, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -264,18 +264,18 @@ medusa.customers.resetPassword({ ```ts fetch(`/store/customers/password-reset`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ email, password, - token - }) + token, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -302,11 +302,11 @@ You can edit a customer’s info using the [Update Customer](/api/store/#tag/Cus ```ts medusa.customers.update({ - first_name + first_name, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -314,16 +314,16 @@ medusa.customers.update({ ```ts fetch(`/store/customers/me`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - first_name - }) + first_name, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -365,12 +365,12 @@ medusa.customers.addresses.addAddress({ company, address_2, province, - metadata - } + metadata, + }, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -378,8 +378,8 @@ medusa.customers.addresses.addAddress({ ```ts fetch(`/store/customers/me/addresses`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ address: { first_name, @@ -392,14 +392,14 @@ fetch(`/store/customers/me/addresses`, { company, address_2, province, - metadata - } - }) + metadata, + }, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -427,11 +427,11 @@ You can edit a customer’s shipping address using the [Update a Shipping Addres ```ts medusa.customers.addresses.updateAddress(addressId, { - first_name + first_name, }) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -439,16 +439,16 @@ medusa.customers.addresses.updateAddress(addressId, { ```ts fetch(`/store/customers/me/addresses/${addressId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - first_name - }) + first_name, + }), }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -468,8 +468,8 @@ You can delete a shipping address by sending a request to the [Delete an Address ```ts medusa.customers.addresses.deleteAddress(addressId) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -477,13 +477,13 @@ medusa.customers.addresses.deleteAddress(addressId) ```ts fetch(`/store/customers/me/addresses/${addressId}`, { - method: 'DELETE', - credentials: 'include' + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ customer }) => { - console.log(customer.id); -}); + console.log(customer.id) +}) ``` @@ -505,8 +505,8 @@ You can retrieve a customer’s orders by sending a request to the [List Orders] ```ts medusa.customers.listOrders() .then(({ orders, limit, offset, count }) => { - console.log(orders); -}); + console.log(orders) +}) ``` @@ -514,12 +514,12 @@ medusa.customers.listOrders() ```ts fetch(`/store/customers/me/orders`, { - credentials: 'include' + credentials: "include", }) .then((response) => response.json()) .then(({ orders, limit, offset, count }) => { - console.log(orders); -}); + console.log(orders) +}) ``` diff --git a/docs/content/advanced/storefront/handle-order-edits.mdx b/docs/content/advanced/storefront/handle-order-edits.mdx index 23adf75435b58..91ddeb5cda8f9 100644 --- a/docs/content/advanced/storefront/handle-order-edits.mdx +++ b/docs/content/advanced/storefront/handle-order-edits.mdx @@ -78,9 +78,9 @@ You can retrieve a single order edit by its ID by sending a request to the [Get ```ts medusa.orderEdits.retrieve(orderEditId) .then(({ order_edit }) => { - console.log(order_edit.changes); - //show changed items to the customer -}); + console.log(order_edit.changes) + // show changed items to the customer +}) ``` @@ -90,9 +90,9 @@ medusa.orderEdits.retrieve(orderEditId) fetch(`/store/order-edits/${orderEditId}`) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.changes); - //show changed items to the customer -}); + console.log(order_edit.changes) + // show changed items to the customer +}) ``` @@ -116,6 +116,8 @@ You can learn more about what fields to expect in the [API reference](/api/store All data about changes to the original order’s items can be found in `order_edit.changes`. `changes` is an array of item changes. Each item change includes the following fields: + + ```ts { type: string, @@ -134,14 +136,22 @@ Here’s an example of how you can use this data to show the customer the reques ```jsx
    - {orderEdit.changes.map(itemChange => ( + {orderEdit.changes.map((itemChange) => (
  • - {itemChange.line_item ? itemChange.line_item.title : itemChange.original_line_item.title} - {itemChange.type === 'added' && New Item} - {itemChange.type === 'removed' && Removed Item} - {itemChange.type === 'edited' && + + { + itemChange.line_item ? + itemChange.line_item.title : + itemChange.original_line_item.title + } + + {itemChange.type === "added" && New Item} + {itemChange.type === "removed" && Removed Item} + {itemChange.type === "edited" && - Edited Item. Old Quantity: {itemChange.original_line_item.quantity}. New Quantity: {itemChange.line_item.quantity} + Edited Item + Old Quantity: {itemChange.original_line_item.quantity} + New Quantity: {itemChange.line_item.quantity} }
  • ))} @@ -178,31 +188,34 @@ If `difference_due` is greater than 0, then additional payment from the customer ```ts medusa.paymentCollections.managePaymentSession(paymentCollectionId, { - provider_id + provider_id, }) .then(({ payment_collection }) => { - console.log(payment_collection.payment_sessions); -}); + console.log(payment_collection.payment_sessions) +}) ``` ```ts -fetch(`/store/payment-collections/${paymentCollectionId}/sessions`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - provider_id - }) -}) +fetch( + `/store/payment-collections/${paymentCollectionId}/sessions`, + { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + provider_id, + }), + } +) .then((response) => response.json()) .then(({ payment_collection }) => { - console.log(payment_collection.payment_sessions); -}); + console.log(payment_collection.payment_sessions) +}) ``` @@ -215,24 +228,29 @@ fetch(`/store/payment-collections/${paymentCollectionId}/sessions`, ```ts -medusa.paymentCollection.authorizePaymentSession(paymentCollectionId, paymentSessionId) +medusa.paymentCollection + .authorizePaymentSession(paymentCollectionId, paymentSessionId) .then(({ payment_session }) => { - console.log(payment_session.id); -}); + console.log(payment_session.id) +}) ``` ```ts -fetch(`/store/payment-collection/${paymentCollectionId}/sessions/${paymentSessionId}/authorize`, { - method: 'POST', - credentials: 'include', -}) +fetch( + `/store/payment-collection/${paymentCollectionId}` + + `/sessions/${paymentSessionId}/authorize`, + { + method: "POST", + credentials: "include", + } +) .then((response) => response.json()) .then(({ payment_session }) => { - console.log(payment_session.id); -}); + console.log(payment_session.id) +}) ``` @@ -252,8 +270,8 @@ To confirm and complete the order edit, send a request to the [Complete Order Ed ```ts medusa.orderEdits.complete(orderEditId) .then(({ order_edit }) => { - console.log(order_edit.confirmed_at); -}); + console.log(order_edit.confirmed_at) +}) ``` @@ -261,13 +279,13 @@ medusa.orderEdits.complete(orderEditId) ```ts fetch(`/store/order-edits/${orderEditId}/complete`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.confirmed_at); -}); + console.log(order_edit.confirmed_at) +}) ``` @@ -296,11 +314,11 @@ If the customer wants to decline the Order Edit, you can do that by sending a re ```ts medusa.orderEdits.decline(orderEditId, { - decline_reason: 'I am not satisfied' + decline_reason: "I am not satisfied", }) .then(({ order_edit }) => { - console.log(order_edit.declined_at); -}); + console.log(order_edit.declined_at) +}) ``` @@ -308,19 +326,19 @@ medusa.orderEdits.decline(orderEditId, { ```ts fetch(`/store/order-edits/${orderEditId}/decline`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - decline_reason: 'I am not satisfied' - }) + decline_reason: "I am not satisfied", + }), }) .then((response) => response.json()) .then(({ order_edit }) => { - console.log(order_edit.declined_at); -}); + console.log(order_edit.declined_at) +}) ``` diff --git a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx index 927234691b0ca..307d7c276b50f 100644 --- a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx +++ b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx @@ -64,11 +64,11 @@ medusa.carts.update(cartId, { country_code, province, postal_code, - phone + phone, }, }) .then(({ cart }) => { - console.log(cart.shipping_address); + console.log(cart.shipping_address) }) ``` @@ -77,8 +77,8 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ shipping_address: { company, @@ -90,17 +90,17 @@ fetch(`/store/carts/${cartId}`, { country_code, province, postal_code, - phone + phone, }, }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response) => response.json()) .then(({ cart }) => { - console.log(cart.shipping_address); -}); + console.log(cart.shipping_address) +}) ``` @@ -124,7 +124,7 @@ You can retrieve the list of shipping options by sending a `GET` request to the ```jsx medusa.shippingOptions.listCartOptions(cartId) .then(({ shipping_options }) => { - console.log(shipping_options.length); + console.log(shipping_options.length) }) ``` @@ -133,11 +133,11 @@ medusa.shippingOptions.listCartOptions(cartId) ```jsx fetch(`/store/shipping-options/${cartId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ shipping_options }) => { - console.log(shipping_options.length); + console.log(shipping_options.length) }) ``` @@ -155,7 +155,7 @@ Once the customer chooses one of the available shipping options, send a `POST` r ```jsx medusa.carts.addShippingMethod(cartId, { - option_id: shippingOptionId //the ID of the selected option + option_id: shippingOptionId, // the ID of the selected option }) .then(({ cart }) => { console.log(cart.shipping_methods) @@ -167,14 +167,14 @@ medusa.carts.addShippingMethod(cartId, { ```jsx fetch(`/store/carts/${cartId}/shipping-methods`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - option_id: shippingOptionId //the ID of the selected option + option_id: shippingOptionId, // the ID of the selected option }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response) => response.json()) .then(({ cart }) => { @@ -216,8 +216,8 @@ medusa.carts.createPaymentSessions(cartId) ```jsx fetch(`/store/carts/${cartId}/payment-sessions`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ cart }) => { @@ -239,7 +239,8 @@ When the customer chooses the payment provider they want to complete purchase wi ```jsx medusa.carts.setPaymentSession(cartId, { - provider_id: paymentProviderId // retrieved from the payment session selected by the customer + // retrieved from the payment session selected by the customer + provider_id: paymentProviderId, }) .then(({ cart }) => { console.log(cart.payment_session) @@ -251,14 +252,15 @@ medusa.carts.setPaymentSession(cartId, { ```jsx fetch(`/store/carts/${cartId}/payment-session`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - provider_id: paymentProviderId // retrieved from the payment session selected by the customer + // retrieved from the payment session selected by the customer + provider_id: paymentProviderId, }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response) => response.json()) .then(({ cart }) => { @@ -291,10 +293,10 @@ If you need to update that data at any point before the purchase is made, send a ```jsx medusa.carts.updatePaymentSession(cartId, paymentProviderId, { data: { - //pass any data you want to add in the `data` attribute - //for example: - "test": true - } + // pass any data you want to add in the `data` attribute + // for example: + "test": true, + }, }) .then(({ cart }) => { console.log(cart.payment_session.data) @@ -304,21 +306,26 @@ medusa.carts.updatePaymentSession(cartId, paymentProviderId, { + + ```jsx -fetch(`/store/carts/${cartId}/payment-sessions/${paymentProviderId}`, { - method: 'POST', - credentials: 'include', - body: JSON.stringify({ - data: { - //pass any data you want to add in the `data` attribute - //for example: - "test": true - } - }), - headers: { - 'Content-Type': 'application/json' +fetch( + `/store/carts/${cartId}/payment-sessions/${paymentProviderId}`, + { + method: "POST", + credentials: "include", + body: JSON.stringify({ + data: { + // pass any data you want to add in the `data` attribute + // for example: + "test": true, + }, + }), + headers: { + "Content-Type": "application/json", + }, } -}) +) .then((response) => response.json()) .then(({ cart }) => { console.log(cart.payment_session.data) @@ -344,7 +351,7 @@ To complete a cart, send a `POST` request to the [Complete a Cart](/api/store/#t ```jsx medusa.carts.complete(cartId) .then(({ type, data }) => { - console.log(type, data); + console.log(type, data) }) ``` @@ -353,15 +360,15 @@ medusa.carts.complete(cartId) ```jsx fetch(`/store/carts/${cartId}/complete`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response) => response.json()) .then(({ type, data }) => { - console.log(type, data); + console.log(type, data) }) ``` diff --git a/docs/content/advanced/storefront/implement-claim-order.mdx b/docs/content/advanced/storefront/implement-claim-order.mdx index 77129496d6a69..ea62a6dd7c88b 100644 --- a/docs/content/advanced/storefront/implement-claim-order.mdx +++ b/docs/content/advanced/storefront/implement-claim-order.mdx @@ -82,7 +82,7 @@ medusa.orders.claimOrders({ }) .catch(() => { // an error occurred -}); +}) ``` @@ -90,23 +90,23 @@ medusa.orders.claimOrders({ ```tsx fetch(`/store/orders/batch/customer/token`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ order_ids: [ order_id, ], }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then(() => { - //successful + // successful }) .catch(() => { - //display an error to the customer -}); + // display an error to the customer +}) ``` @@ -131,14 +131,14 @@ Then, you send a request to the Verify Claim Order endpoint: ```tsx medusa.orders.confirmRequest({ - token + token, }) .then(() => { // successful }) .catch(() => { // an error occurred -}); +}) ``` @@ -146,21 +146,21 @@ medusa.orders.confirmRequest({ ```tsx fetch(`/store/orders/customer/confirm`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - token + token, }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then(() => { - //successful + // successful }) .catch(() => { - //display an error to the customer -}); + // display an error to the customer +}) ``` diff --git a/docs/content/advanced/storefront/use-discounts-in-checkout.mdx b/docs/content/advanced/storefront/use-discounts-in-checkout.mdx index cb8905c5ba2fe..e7398ffaaafc4 100644 --- a/docs/content/advanced/storefront/use-discounts-in-checkout.mdx +++ b/docs/content/advanced/storefront/use-discounts-in-checkout.mdx @@ -58,17 +58,17 @@ You can add a discount to a customer’s cart by sending the [Update Cart reques medusa.carts.update(cartId, { discounts: [ { - code - } - ] + code, + }, + ], }) .then(({ cart }) => { console.log(cart.discounts) }) .catch((e) => { - //display an error to the customer - alert('Discount is invalid') -}); + // display an error to the customer + alert("Discount is invalid") +}) ``` @@ -76,27 +76,27 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ discounts: [ { - code - } + code, + }, ], }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response) => response.json()) .then(({ cart }) => { - console.log(cart.discounts); + console.log(cart.discounts) }) .catch((e) => { - //display an error to the customer - alert('Discount is invalid') -}); + // display an error to the customer + alert("Discount is invalid") +}) ``` @@ -222,7 +222,7 @@ You can remove a discount from a customer’s cart using the [Remove Discount re medusa.carts.deleteDiscount(cartId, code) .then(({ cart }) => { console.log(cart.discounts) -}); +}) ``` @@ -230,13 +230,13 @@ medusa.carts.deleteDiscount(cartId, code) ```jsx fetch(`/store/carts/${cartId}/discounts/${code}`, { - method: 'DELETE', - credentials: 'include' + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) .then(({ cart }) => { - console.log(cart.discounts); -}); + console.log(cart.discounts) +}) ``` diff --git a/docs/content/advanced/storefront/use-regions.mdx b/docs/content/advanced/storefront/use-regions.mdx index 9b5d9a7f7e20e..64f0be708f2dd 100644 --- a/docs/content/advanced/storefront/use-regions.mdx +++ b/docs/content/advanced/storefront/use-regions.mdx @@ -47,9 +47,9 @@ You can retrieve available regions by sending a request to the [List Regions](/a ```tsx medusa.regions.list() .then(({ regions }) => { - console.log(regions.length); - //show customers available regions -}); + console.log(regions.length) + // show customers available regions +}) ``` @@ -57,13 +57,13 @@ medusa.regions.list() ```tsx fetch(`/store/regions`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ regions }) => { - console.log(regions.length); - //show customers available regions -}); + console.log(regions.length) + // show customers available regions +}) ``` @@ -86,12 +86,12 @@ For example: ```tsx medusa.products.list({ - region_id: regionId + region_id: regionId, }) .then(({ products, limit, offset, count }) => { - console.log(products.length); - //show customer the products -}); + console.log(products.length) + // show customer the products +}) ``` @@ -99,13 +99,13 @@ medusa.products.list({ ```tsx fetch(`/store/products?region_id=${regionId}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) .then(({ products, limit, offset, count }) => { - console.log(products.length); - //show customer the products -}); + console.log(products.length) + // show customer the products +}) ``` @@ -136,11 +136,11 @@ For example: ```tsx medusa.carts.update(cartId, { - region_id: regionId + region_id: regionId, }) .then(({ cart }) => { - console.log(cart.id); -}); + console.log(cart.id) +}) ``` @@ -148,16 +148,16 @@ medusa.carts.update(cartId, { ```tsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", body: JSON.stringify({ - region_id: regionId - }) + region_id: regionId, + }), }) .then((response) => response.json()) .then(({ cart }) => { - console.log(cart.id); -}); + console.log(cart.id) +}) ``` diff --git a/docs/content/advanced/storefront/use-sales-channels.mdx b/docs/content/advanced/storefront/use-sales-channels.mdx index 97735f3d25fb4..712b53898fd12 100644 --- a/docs/content/advanced/storefront/use-sales-channels.mdx +++ b/docs/content/advanced/storefront/use-sales-channels.mdx @@ -39,12 +39,12 @@ To filter products by a specific sales channel, pass the `sales_channel_id` quer ```jsx medusa.products.list({ sales_channel_id: [ - salesChannelId - ] + salesChannelId, + ], }) .then(({ products, limit, offset, count }) => { - console.log(products.length); -}); + console.log(products.length) +}) ``` @@ -55,7 +55,7 @@ fetch(`/store/products?sales_channel_id[0]=${salesChannelId}`) .then((response) => response.json()) .then(({ products, limit, offset, count }) => { console.log(products.length) -}); +}) ``` @@ -79,11 +79,11 @@ To associate a sales channel with a cart while creating it, you can pass the `sa ```jsx medusa.carts.create({ - sales_channel_id: salesChannelId + sales_channel_id: salesChannelId, +}) +.then(({ cart }) => { + console.log(cart.id) }) -.then(({cart}) => { - console.log(cart.id); -}); ``` @@ -91,18 +91,18 @@ medusa.carts.create({ ```jsx fetch(`/store/carts`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - sales_channel_id: salesChannelId - }) + sales_channel_id: salesChannelId, + }), }) .then((response) => response.json()) -.then(({cart}) => { - console.log(cart.id); -}); +.then(({ cart }) => { + console.log(cart.id) +}) ``` @@ -119,11 +119,11 @@ You can update the sales channel of an existing cart by passing the `sales_chann ```jsx medusa.carts.update(cartId, { - sales_channel_id: salesChannelId + sales_channel_id: salesChannelId, +}) +.then(({ cart }) => { + console.log(cart.id) }) -.then(({cart}) => { - console.log(cart.id); -}); ``` @@ -131,16 +131,16 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - sales_channel_id: salesChannelId - }) + sales_channel_id: salesChannelId, + }), }) .then((response) => response.json()) -.then(({cart}) => console.log(cart.id)); +.then(({ cart }) => console.log(cart.id)) ``` diff --git a/docs/content/contribution-guidelines.md b/docs/content/contribution-guidelines.md index 9216a7f7a8c0c..30d3fda39188d 100644 --- a/docs/content/contribution-guidelines.md +++ b/docs/content/contribution-guidelines.md @@ -130,10 +130,10 @@ import TabItem from '@theme/TabItem'; ```jsx -medusa.admin.uploads.create(file) //file is an instance of File +medusa.admin.uploads.create(file) // file is an instance of File .then(({ uploads }) => { - const key = uploads[0].key; -}); + const key = uploads[0].key +}) ``` @@ -157,7 +157,10 @@ If you want to add a title to a code block with tabs, add the `codeTitle` prop t For example: ```md - + ``` ### Add Title to Code Block without Tabs @@ -242,7 +245,7 @@ npm install @medusajs/medusa-cli -g Medusa uses Vale to lint documentation pages and perform checks on incoming PRs into the repository. -### Result of PR Checks +### Result of Vale PR Checks You can check the result of running the "lint" action on your PR by clicking the Details link next to it. You can find there all errors that you need to fix. @@ -293,6 +296,64 @@ If you use this in your PR, you must justify its usage. --- +## Linting with ESLint + +Medusa uses Eslint to lint code blocks in the documentation and perform checks on incoming PRs into the repository. + +### Result of ESLint PR Checks + +You can check the result of running the "eslint" action on your PR by clicking the Details link next to it. You can find there all errors that you need to fix. + +### Running ESLint locally + +If you want to check your work locally, you can do that by: + +1. Installing the dependencies in the root directory: + +```bash +yarn install +``` + +2\. Run the lint command: + +```bash +yarn lint:docs +``` + +You can also pass the `--fix` option to automatically fix errors. + +### ESLint Exceptions + +If some code blocks have errors that can't or shouldn't be fixed, you can add the following command before the code block: + +~~~md + + +```js +console.log("This block isn't linted") +``` + +```js +console.log("This block is linted") +``` +~~~ + +You can also disable specific rules. For example: + +~~~md + + +```js +console.log("This block can use semicolons"); +``` + +```js +console.log("This block can't use semi colons") +``` +~~~ + +--- + ## Need Additional Help If you need any additional help while contributing, you can join Medusa's [Discord server](https://discord.gg/medusajs) and ask Medusa’s core team as well as the community any questions. diff --git a/docs/content/deployments/server/deploying-on-digital-ocean.md b/docs/content/deployments/server/deploying-on-digital-ocean.md index 5f1d6c18b32a0..dffef96150c3c 100644 --- a/docs/content/deployments/server/deploying-on-digital-ocean.md +++ b/docs/content/deployments/server/deploying-on-digital-ocean.md @@ -52,13 +52,15 @@ In `medusa-config.js`, the `DATABASE_URL` variable is set to the environment var Replace the previous declaration of `DATABASE_URL` in `medusa-config.js` with the following: ```js -const DB_USERNAME = process.env.DB_USERNAME; -const DB_PASSWORD = process.env.DB_PASSWORD; -const DB_HOST = process.env.DB_HOST; -const DB_PORT = process.env.DB_PORT; -const DB_DATABASE = process.env.DB_DATABASE; - -const DATABASE_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}`; +const DB_USERNAME = process.env.DB_USERNAME +const DB_PASSWORD = process.env.DB_PASSWORD +const DB_HOST = process.env.DB_HOST +const DB_PORT = process.env.DB_PORT +const DB_DATABASE = process.env.DB_DATABASE + +const DATABASE_URL = + `postgres://${DB_USERNAME}:${DB_PASSWORD}` + + `@${DB_HOST}:${DB_PORT}/${DB_DATABASE}` ``` In addition, you must add to `projectConfig` in the exported object a new property `database_extra`: @@ -66,10 +68,10 @@ In addition, you must add to `projectConfig` in the exported object a new proper ```js module.exports = { projectConfig: { - //... - database_extra: { ssl: { rejectUnauthorized: false } } + // ... + database_extra: { ssl: { rejectUnauthorized: false } }, }, -}; +} ``` --- diff --git a/docs/content/deployments/server/deploying-on-heroku.mdx b/docs/content/deployments/server/deploying-on-heroku.mdx index 2378efa73ac67..57df2d8de9b32 100644 --- a/docs/content/deployments/server/deploying-on-heroku.mdx +++ b/docs/content/deployments/server/deploying-on-heroku.mdx @@ -187,7 +187,7 @@ module.exports = { : {}, }, plugins, -}; +} ``` #### package.json diff --git a/docs/content/guides/carts-in-medusa.mdx b/docs/content/guides/carts-in-medusa.mdx index ea466b68eed22..979a74e2c9060 100644 --- a/docs/content/guides/carts-in-medusa.mdx +++ b/docs/content/guides/carts-in-medusa.mdx @@ -49,10 +49,10 @@ You can create a cart with the following code snippet: ```jsx medusa.carts.create() .then(({ cart }) => { - localStorage.setItem('cart_id', cart.id); - //assuming you have a state variable to store the cart - setCart(cart); -}); + localStorage.setItem("cart_id", cart.id) + // assuming you have a state variable to store the cart + setCart(cart) +}) ``` @@ -60,15 +60,15 @@ medusa.carts.create() ```jsx fetch(`/store/carts`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", }) .then((response) => response.json()) .then(({ cart }) => { - localStorage.setItem('cart_id', cart.id); - //assuming you have a state variable to store the cart + localStorage.setItem("cart_id", cart.id) + // assuming you have a state variable to store the cart setCart(cart) -}); +}) ``` @@ -85,13 +85,13 @@ Otherwise, you can assign it a specific region during creation: ```jsx medusa.carts.create({ - region_id + region_id, }) .then(({ cart }) => { - localStorage.setItem('cart_id', cart.id); - //assuming you have a state variable to store the cart - setCart(cart); -}); + localStorage.setItem("cart_id", cart.id) + // assuming you have a state variable to store the cart + setCart(cart) +}) ``` @@ -99,21 +99,21 @@ medusa.carts.create({ ```jsx fetch(`/store/carts`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - region_id - }) + region_id, + }), }) .then((response) => response.json()) .then(({ cart }) => { - localStorage.setItem('cart_id', cart.id); - //assuming you have a state variable to store the cart + localStorage.setItem("cart_id", cart.id) + // assuming you have a state variable to store the cart setCart(cart) -}); +}) ``` @@ -139,11 +139,11 @@ You can retrieve the cart at any given point using its ID with the following cod ```jsx -const id = localStorage.getItem('cart_id'); +const id = localStorage.getItem("cart_id") if (id) { medusa.carts.retrieve(id) - .then(({ cart }) => setCart(cart)); + .then(({ cart }) => setCart(cart)) } ``` @@ -151,14 +151,14 @@ if (id) { ```jsx -const id = localStorage.getItem('cart_id'); +const id = localStorage.getItem("cart_id") if (id) { fetch(`/store/carts/${id}`, { - credentials: 'include', + credentials: "include", }) .then((response) => response.json()) - .then(({ cart }) => setCart(cart)); + .then(({ cart }) => setCart(cart)) } ``` @@ -188,9 +188,9 @@ You can use the following snippet to update any of the cart’s data: ```jsx medusa.carts.update(cartId, { - region_id + region_id, }) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -198,17 +198,17 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - region_id - }) + region_id, + }), }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -231,9 +231,9 @@ You can do that using the same update operation: ```jsx medusa.carts.update(cartId, { - customer_id + customer_id, }) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -241,17 +241,17 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - customer_id - }) + customer_id, + }), }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -270,9 +270,9 @@ You can do that using the same update operation: ```jsx medusa.carts.update(cartId, { - email: 'user@example.com' + email: "user@example.com", }) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -280,17 +280,17 @@ medusa.carts.update(cartId, { ```jsx fetch(`/store/carts/${cartId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - email: 'user@example.com' - }) + email: "user@example.com", + }), }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -308,9 +308,9 @@ To create a line item of a product and add it to a cart, you can use the followi ```jsx medusa.carts.lineItems.create(cartId, { variant_id, - quantity: 1 + quantity: 1, }) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -318,18 +318,18 @@ medusa.carts.lineItems.create(cartId, { ```jsx fetch(`/store/carts/${cartId}/line-items`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ variant_id, - quantity: 1 - }) + quantity: 1, + }), }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -358,7 +358,7 @@ To update a line item's quantity in the cart, you can use the following code sni ```jsx medusa.carts.lineItems.update(cartId, lineItemId, { - quantity: 3 + quantity: 3, }) .then(({ cart }) => setCart(cart)) ``` @@ -368,17 +368,17 @@ medusa.carts.lineItems.update(cartId, lineItemId, { ```jsx fetch(`/store/carts/${cartId}/line-items/${lineItemId}`, { - method: 'POST', - credentials: 'include', + method: "POST", + credentials: "include", headers: { - 'Content-Type': 'application/json' + "Content-Type": "application/json", }, body: JSON.stringify({ - quantity: 3 - }) + quantity: 3, + }), }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` @@ -407,11 +407,11 @@ medusa.carts.lineItems.delete(cartId, lineItemId) ```jsx fetch(`/store/carts/${cartId}/line-items/${lineItemId}`, { - method: 'DELETE', - credentials: 'include', + method: "DELETE", + credentials: "include", }) .then((response) => response.json()) -.then(({ cart }) => setCart(cart)); +.then(({ cart }) => setCart(cart)) ``` diff --git a/docs/content/js-client/overview.md b/docs/content/js-client/overview.md index 258932330422d..4b5e254cdc2bf 100644 --- a/docs/content/js-client/overview.md +++ b/docs/content/js-client/overview.md @@ -37,9 +37,9 @@ import Medusa from "@medusajs/medusa-js" const medusa = new Medusa() -//use method +// use method medusa.customers.create({ - //data + // data }) ``` @@ -47,7 +47,7 @@ The `customers` resource also has another resource `addresses` nested inside it ```js medusa.customers.addresses.addAddress({ - //data + // data }) ``` diff --git a/docs/content/troubleshooting/cors-issues.md b/docs/content/troubleshooting/cors-issues.md index 9895e65a33e81..73372a435a384 100644 --- a/docs/content/troubleshooting/cors-issues.md +++ b/docs/content/troubleshooting/cors-issues.md @@ -10,9 +10,10 @@ In your `medusa-config.js` , you should ensure that you've configured your CORS The default configuration uses the following CORS settings: -```jsx title=medusa-config.js +```js title=medusa-config.js // CORS when consuming Medusa from admin -const ADMIN_CORS = process.env.ADMIN_CORS || "http://localhost:7000,http://localhost:7001" +const ADMIN_CORS = process.env.ADMIN_CORS || + "http://localhost:7000,http://localhost:7001" // CORS to avoid issues when consuming Medusa from a client const STORE_CORS = process.env.STORE_CORS || "http://localhost:8000" diff --git a/docs/content/troubleshooting/missing-payment-providers.md b/docs/content/troubleshooting/missing-payment-providers.md index ed3a26f0da492..95d33da338d2a 100644 --- a/docs/content/troubleshooting/missing-payment-providers.md +++ b/docs/content/troubleshooting/missing-payment-providers.md @@ -2,9 +2,9 @@ You add payment providers to your Medusa instance by adding them as plugins in `medusa-config.js`: -```jsx title=medusa-config.js +```js title=medusa-config.js const plugins = [ - ... + // ... // You can create a Stripe account via: https://stripe.com { resolve: `medusa-payment-stripe`, @@ -13,8 +13,7 @@ const plugins = [ webhook_secret: STRIPE_WEBHOOK_SECRET, }, }, - ... -]; +] ``` And installing them with your favourite package manager: diff --git a/docs/content/troubleshooting/redis-events.md b/docs/content/troubleshooting/redis-events.md index 30140eb6d6e85..8ddf29c1c724a 100644 --- a/docs/content/troubleshooting/redis-events.md +++ b/docs/content/troubleshooting/redis-events.md @@ -11,7 +11,7 @@ After installing it, make sure to configure your Medusa server to use Redis: ```jsx title=medusa-config.js module.exports = { projectConfig: { - //... + // ... redis_url: REDIS_URL, }, } diff --git a/docs/content/troubleshooting/transaction-error-in-checkout.md b/docs/content/troubleshooting/transaction-error-in-checkout.md index bc9d555fe37e9..d6537381ab3d1 100644 --- a/docs/content/troubleshooting/transaction-error-in-checkout.md +++ b/docs/content/troubleshooting/transaction-error-in-checkout.md @@ -19,7 +19,7 @@ Then in your `medusa-config.js`, you should change the project configuration to ```jsx title=medusa-config.js module.exports = { projectConfig: { - //... + // ... database_url: DATABASE_URL, database_type: "postgres", }, @@ -31,6 +31,8 @@ Where `DATABASE_URL` is the connection string to your PostgreSQL database. You c Make sure to also remove the following lines that are used to configure an SQLite database: + + ```jsx title=medusa-config.js database_type: "sqlite", database_database: "./medusa-db.sql", diff --git a/docs/content/usage/configurations.md b/docs/content/usage/configurations.md index 1ad4a834a6987..ad5a6f66611b0 100644 --- a/docs/content/usage/configurations.md +++ b/docs/content/usage/configurations.md @@ -47,11 +47,11 @@ For SQLite you mainly need two configurations: ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations database_type: "sqlite", database_database: "./medusa-db.sql", }, -}; +} ``` Where `database_type` is `sqlite` and `database_database` is the location you want the SQLite database to be created in. @@ -69,12 +69,12 @@ For PostgreSQL you mainly need two configurations: ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations database_type: "postgres", database_url: DATABASE_URL, - database_schema: process.env.DATABASE_SCHEMA //optional + database_schema: process.env.DATABASE_SCHEMA, // optional }, -}; +} ``` Where `database_type` is `postgres` and `DATABASE_URL` is the URL connection string to your PostgreSQL database. You can check out how to format it in [PostgreSQL’s documentation](https://www.postgresql.org/docs/current/libpq-connect.html). @@ -109,11 +109,11 @@ These configurations are not required and can be omitted. ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations database_logging: true, - database_extra: {} + database_extra: {}, }, -}; +} ``` --- @@ -125,10 +125,10 @@ Medusa uses Redis to handle the event queue, among other usages. You need to set ```jsx module.exports = { projectConfig: { - //...other configurations - redis_url: REDIS_URL + // ...other configurations + redis_url: REDIS_URL, }, -}; +} ``` Where `REDIS_URL` is the URL used to connect to Redis. The format of the connection string is `redis[s]://[[username][:password]@][host][:port][/db-number]`. @@ -164,10 +164,10 @@ Medusa uses JSON Web Token (JWT) to handle user authentication. To set the JWT s ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations jwt_secret: "very secure string", }, -}; +} ``` Where `jwt_secret` is the secret used to create the tokens. The more secure it is the better. @@ -195,10 +195,10 @@ This configuration is used to sign the session ID cookie. To set the cookie secr ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations cookie_secret: "very secure string", }, -}; +} ``` Where `cookie_secret` is the secret used to create the tokens. The more secure it is the better. @@ -239,10 +239,10 @@ To make sure your Admin dashboard can access the Medusa server’s admin endpoin ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations admin_cors: ADMIN_CORS, }, -}; +} ``` Where `ADMIN_CORS` is the URL of your admin dashboard. By default, it’s `http://localhost:7000,http://localhost:7001`. @@ -268,10 +268,10 @@ To make sure your Storefront dashboard can access the Medusa server, set this co ```jsx module.exports = { projectConfig: { - //...other configurations + // ...other configurations store_cors: STORE_CORS, }, -}; +} ``` Where `STORE_CORS` is the URL of your storefront. By default, it’s `http://localhost:8000`. @@ -307,10 +307,10 @@ Aside from installing the plugin with NPM, you need to pass the plugin you insta ```jsx module.exports = { projectConfig: { - //previous configurations mentioned... + // previous configurations mentioned... }, plugins, -}; +} ``` ### Add a Plugin Without Configuration @@ -319,9 +319,9 @@ To add a plugin that doesn’t need any configurations, you can simply add its n ```jsx const plugins = [ - //other plugins... + // other plugins... `medusa-my-plugin`, -]; +] ``` ### Add a Plugin With Configuration @@ -330,14 +330,14 @@ To add a plugin with configurations, you need to add an object to the `plugins` ```jsx const plugins = [ - //other plugins... + // other plugins... { resolve: `medusa-my-plugin`, options: { - apiKey: `test` - } - } -]; + apiKey: `test`, + }, + }, +] ``` :::tip diff --git a/package.json b/package.json index c19084b42697c..fcdf8d041f687 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@babel/plugin-transform-instanceof": "^7.10.4", "@babel/plugin-transform-runtime": "^7.11.5", "@babel/preset-env": "^7.11.5", + "@babel/preset-react": "^7.18.6", "@babel/register": "^7.11.5", "@babel/runtime": "^7.11.2", "@redocly/cli": "latest", @@ -29,7 +30,9 @@ "eslint": "^8.23.0", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-markdown": "^3.0.0", "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.31.11", "express": "^4.17.1", "get-port": "^5.1.1", "husky": "^7.0.2", @@ -60,6 +63,7 @@ "hooks:uninstall": "husky uninstall", "build": "turbo run build --no-daemon", "lint": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx .", + "lint:docs": "eslint -c docs/.eslintrc.js --ignore-path docs/.eslintignore docs/content", "prettier": "prettier", "jest": "jest", "test": "turbo run test --no-daemon --filter=!integration-tests-api --filter=!integration-tests-plugins", diff --git a/yarn.lock b/yarn.lock index c8773f73be7b5..e7c74d45f0385 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1826,7 +1826,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.12.10, @babel/preset-react@npm:^7.14.0": +"@babel/preset-react@npm:^7.12.10, @babel/preset-react@npm:^7.14.0, @babel/preset-react@npm:^7.18.6": version: 7.18.6 resolution: "@babel/preset-react@npm:7.18.6" dependencies: @@ -9888,6 +9888,19 @@ __metadata: languageName: node linkType: hard +"array-includes@npm:^3.1.6": + version: 3.1.6 + resolution: "array-includes@npm:3.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + get-intrinsic: ^1.1.3 + is-string: ^1.0.7 + checksum: d0caeaa57bea7d14b8480daee30cf8611899321006b15a6cd872b831bd7aaed7649f8764e060d01c5d33b8d9e998e5de5c87f4901874e1c1f467f429b7db2929 + languageName: node + linkType: hard + "array-union@npm:^1.0.2": version: 1.0.2 resolution: "array-union@npm:1.0.2" @@ -9942,6 +9955,18 @@ __metadata: languageName: node linkType: hard +"array.prototype.flatmap@npm:^1.3.1": + version: 1.3.1 + resolution: "array.prototype.flatmap@npm:1.3.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + es-shim-unscopables: ^1.0.0 + checksum: 2bd58a0e79d5d90cb4f5ef0e287edf8b28e87c65428f54025ac6b7b4c204224b92811c266f296c53a2dbc93872117c0fcea2e51d3c9e8cecfd5024d4a4a57db4 + languageName: node + linkType: hard + "array.prototype.map@npm:^1.0.4": version: 1.0.4 resolution: "array.prototype.map@npm:1.0.4" @@ -9968,6 +9993,19 @@ __metadata: languageName: node linkType: hard +"array.prototype.tosorted@npm:^1.1.1": + version: 1.1.1 + resolution: "array.prototype.tosorted@npm:1.1.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + es-shim-unscopables: ^1.0.0 + get-intrinsic: ^1.1.3 + checksum: fd5f57aca3c7ddcd1bb83965457b625f3a67d8f334f5cbdb8ac8ef33d5b0d38281524114db2936f8c08048115d5158af216c94e6ae1eb966241b9b6f4ab8a7e8 + languageName: node + linkType: hard + "arrify@npm:^1.0.1": version: 1.0.1 resolution: "arrify@npm:1.0.1" @@ -13756,7 +13794,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:~4.3.1": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:~4.3.1": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -14894,6 +14932,39 @@ __metadata: languageName: node linkType: hard +"es-abstract@npm:^1.20.4": + version: 1.20.5 + resolution: "es-abstract@npm:1.20.5" + dependencies: + call-bind: ^1.0.2 + es-to-primitive: ^1.2.1 + function-bind: ^1.1.1 + function.prototype.name: ^1.1.5 + get-intrinsic: ^1.1.3 + get-symbol-description: ^1.0.0 + gopd: ^1.0.1 + has: ^1.0.3 + has-property-descriptors: ^1.0.0 + has-symbols: ^1.0.3 + internal-slot: ^1.0.3 + is-callable: ^1.2.7 + is-negative-zero: ^2.0.2 + is-regex: ^1.1.4 + is-shared-array-buffer: ^1.0.2 + is-string: ^1.0.7 + is-weakref: ^1.0.2 + object-inspect: ^1.12.2 + object-keys: ^1.1.1 + object.assign: ^4.1.4 + regexp.prototype.flags: ^1.4.3 + safe-regex-test: ^1.0.0 + string.prototype.trimend: ^1.0.6 + string.prototype.trimstart: ^1.0.6 + unbox-primitive: ^1.0.2 + checksum: c99f8a3e9ac15890cde5bf78d1910d72758d3e79c710bd1ad2ab6b595d39ad07209626befaa7c18591bd935a02f6a3bdba3a7e9c8dd6a01146e655df09dc4353 + languageName: node + linkType: hard + "es-array-method-boxes-properly@npm:^1.0.0": version: 1.0.0 resolution: "es-array-method-boxes-properly@npm:1.0.0" @@ -15265,6 +15336,17 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-markdown@npm:^3.0.0": + version: 3.0.0 + resolution: "eslint-plugin-markdown@npm:3.0.0" + dependencies: + mdast-util-from-markdown: ^0.8.5 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 3424fd97b6990cbed7be3764ae8bec7eae9bd1cc03cd76d8d1cf38e088a9777ed4491921e7e1a8d3a146361bcd935e5ed1b2bfd4fd623bcdafdb824bccfdd2b2 + languageName: node + linkType: hard + "eslint-plugin-prettier@npm:^4.2.1": version: 4.2.1 resolution: "eslint-plugin-prettier@npm:4.2.1" @@ -15313,6 +15395,31 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-react@npm:^7.31.11": + version: 7.31.11 + resolution: "eslint-plugin-react@npm:7.31.11" + dependencies: + array-includes: ^3.1.6 + array.prototype.flatmap: ^1.3.1 + array.prototype.tosorted: ^1.1.1 + doctrine: ^2.1.0 + estraverse: ^5.3.0 + jsx-ast-utils: ^2.4.1 || ^3.0.0 + minimatch: ^3.1.2 + object.entries: ^1.1.6 + object.fromentries: ^2.0.6 + object.hasown: ^1.1.2 + object.values: ^1.1.6 + prop-types: ^15.8.1 + resolve: ^2.0.0-next.3 + semver: ^6.3.0 + string.prototype.matchall: ^4.0.8 + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + checksum: 2f8d27adbfe1b551a170cc1340dd8bbecf6c9fdbfcde04dd1097bbf198e99f0c981af84bc3c69f851af5736cc4d6520687a03dfb3271717079f88983d79cb9cd + languageName: node + linkType: hard + "eslint-plugin-testing-library@npm:^5.5.1": version: 5.5.1 resolution: "eslint-plugin-testing-library@npm:5.5.1" @@ -17753,6 +17860,17 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.1.3": + version: 1.1.3 + resolution: "get-intrinsic@npm:1.1.3" + dependencies: + function-bind: ^1.1.1 + has: ^1.0.3 + has-symbols: ^1.0.3 + checksum: 6f201d5f95ea0dd6c8d0dc2c265603aff0b9e15614cb70f8f4674bb3d2b2369d521efaa84d0b70451d2c00762ebd28402758bf46279c6f2a00d242ebac0d8442 + languageName: node + linkType: hard + "get-own-enumerable-property-symbols@npm:^3.0.0": version: 3.0.2 resolution: "get-own-enumerable-property-symbols@npm:3.0.2" @@ -18152,6 +18270,15 @@ __metadata: languageName: node linkType: hard +"gopd@npm:^1.0.1": + version: 1.0.1 + resolution: "gopd@npm:1.0.1" + dependencies: + get-intrinsic: ^1.1.3 + checksum: 505c05487f7944c552cee72087bf1567debb470d4355b1335f2c262d218ebbff805cd3715448fe29b4b380bae6912561d0467233e4165830efd28da241418c63 + languageName: node + linkType: hard + "got@npm:^11.8.2, got@npm:^11.8.5": version: 11.8.5 resolution: "got@npm:11.8.5" @@ -19613,6 +19740,13 @@ __metadata: languageName: node linkType: hard +"is-callable@npm:^1.2.7": + version: 1.2.7 + resolution: "is-callable@npm:1.2.7" + checksum: ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f + languageName: node + linkType: hard + "is-ci@npm:^2.0.0": version: 2.0.0 resolution: "is-ci@npm:2.0.0" @@ -23624,6 +23758,19 @@ __metadata: languageName: node linkType: hard +"mdast-util-from-markdown@npm:^0.8.5": + version: 0.8.5 + resolution: "mdast-util-from-markdown@npm:0.8.5" + dependencies: + "@types/mdast": ^3.0.0 + mdast-util-to-string: ^2.0.0 + micromark: ~2.11.0 + parse-entities: ^2.0.0 + unist-util-stringify-position: ^2.0.0 + checksum: 86e7589e574378817c180f10ab602db844b6b71b7b1769314947a02ef42ac5c1435f5163d02a975ae8cdab8b6e6176acbd9188da1848ddd5f0d5e09d0291c870 + languageName: node + linkType: hard + "mdast-util-to-hast@npm:10.0.1": version: 10.0.1 resolution: "mdast-util-to-hast@npm:10.0.1" @@ -23647,6 +23794,13 @@ __metadata: languageName: node linkType: hard +"mdast-util-to-string@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-to-string@npm:2.0.0" + checksum: a4231085133cdfec24644b694c13661e5a01d26716be0105b6792889faa04b8030e4abbf72d4be3363098b2b38b2b98f1f1f1f0858eb6580dc04e2aca1436a37 + languageName: node + linkType: hard + "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" @@ -24723,6 +24877,16 @@ __metadata: languageName: node linkType: hard +"micromark@npm:~2.11.0": + version: 2.11.4 + resolution: "micromark@npm:2.11.4" + dependencies: + debug: ^4.0.0 + parse-entities: ^2.0.0 + checksum: 67307cbacae621ab1eb23e333a5addc7600cf97d3b40cad22fc1c2d03d734d6d9cbc3f5a7e5d655a8c0862a949abe590ab7cfa96be366bfe09e239a94e6eea55 + languageName: node + linkType: hard + "micromatch@npm:4.x, micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -26102,7 +26266,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.0, object-inspect@npm:^1.9.0": +"object-inspect@npm:^1.12.0, object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": version: 1.12.2 resolution: "object-inspect@npm:1.12.2" checksum: e1bd625f4c44a2f733bd69cfccce6469f71333fb09c6de151f4f346c16d658ef7555727b12652c108e20c2afb908ae7cd165f52ca53745a1d6cbf228cdb46ebe @@ -26154,6 +26318,18 @@ __metadata: languageName: node linkType: hard +"object.assign@npm:^4.1.4": + version: 4.1.4 + resolution: "object.assign@npm:4.1.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + has-symbols: ^1.0.3 + object-keys: ^1.1.1 + checksum: 2f286118c023e557757620e647b02e7c88d3d417e0c568fca0820de8ec9cca68928304854d5b03e99763eddad6e78a6716e2930f7e6372e4b9b843f3fd3056f3 + languageName: node + linkType: hard + "object.entries@npm:^1.1.0, object.entries@npm:^1.1.5": version: 1.1.5 resolution: "object.entries@npm:1.1.5" @@ -26165,6 +26341,17 @@ __metadata: languageName: node linkType: hard +"object.entries@npm:^1.1.6": + version: 1.1.6 + resolution: "object.entries@npm:1.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 8782c71db3a068ccbae9e0541e6b4ac2c25dc67c63f97b7e6ad3c88271d7820197e7398e37747f96542ed47c27f0b81148cdf14c42df15dc22f64818ae7bb5bf + languageName: node + linkType: hard + "object.fromentries@npm:^2.0.0 || ^1.0.0, object.fromentries@npm:^2.0.5": version: 2.0.5 resolution: "object.fromentries@npm:2.0.5" @@ -26176,6 +26363,17 @@ __metadata: languageName: node linkType: hard +"object.fromentries@npm:^2.0.6": + version: 2.0.6 + resolution: "object.fromentries@npm:2.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: db6759ea68131cbdb70b1152f9984b49db03e81de4f6de079b39929bebd8b45501e5333ca2351991e07ee56f4651606c023396644e8f25c0806fa39a26c4c6e6 + languageName: node + linkType: hard + "object.getownpropertydescriptors@npm:^2.0.3, object.getownpropertydescriptors@npm:^2.1.1, object.getownpropertydescriptors@npm:^2.1.2": version: 2.1.4 resolution: "object.getownpropertydescriptors@npm:2.1.4" @@ -26198,6 +26396,16 @@ __metadata: languageName: node linkType: hard +"object.hasown@npm:^1.1.2": + version: 1.1.2 + resolution: "object.hasown@npm:1.1.2" + dependencies: + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 419fc1c74a2aea7ebb4d49b79d5b1599a010b26c18eae35bd061ccdd013ccb749c499d8dd6ee21a91e6d7264ccc592573d0f13562970f76e25fc844d8c1b02ce + languageName: node + linkType: hard + "object.pick@npm:^1.3.0": version: 1.3.0 resolution: "object.pick@npm:1.3.0" @@ -26218,6 +26426,17 @@ __metadata: languageName: node linkType: hard +"object.values@npm:^1.1.6": + version: 1.1.6 + resolution: "object.values@npm:1.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 3381204390f10c9f653a4875a50d221c67b5c16cb80a6ac06c706fc82a7cad8400857d4c7a0731193b0abb56b84fe803eabcf7addcf32de76397bbf207e68c66 + languageName: node + linkType: hard + "objectFitPolyfill@npm:^2.3.5": version: 2.3.5 resolution: "objectFitPolyfill@npm:2.3.5" @@ -30150,6 +30369,7 @@ __metadata: "@babel/plugin-transform-instanceof": ^7.10.4 "@babel/plugin-transform-runtime": ^7.11.5 "@babel/preset-env": ^7.11.5 + "@babel/preset-react": ^7.18.6 "@babel/register": ^7.11.5 "@babel/runtime": ^7.11.2 "@changesets/changelog-github": ^0.4.5 @@ -30167,7 +30387,9 @@ __metadata: eslint: ^8.23.0 eslint-config-google: ^0.14.0 eslint-config-prettier: ^8.5.0 + eslint-plugin-markdown: ^3.0.0 eslint-plugin-prettier: ^4.2.1 + eslint-plugin-react: ^7.31.11 express: ^4.17.1 get-port: ^5.1.1 global: ^4.4.0 @@ -30295,6 +30517,17 @@ __metadata: languageName: node linkType: hard +"safe-regex-test@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-regex-test@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.1.3 + is-regex: ^1.1.4 + checksum: 14a81a7e683f97b2d6e9c8be61fddcf8ed7a02f4e64a825515f96bb1738eb007145359313741d2704d28b55b703a0f6300c749dde7c1dbc13952a2b85048ede2 + languageName: node + linkType: hard + "safe-regex@npm:^1.1.0": version: 1.1.0 resolution: "safe-regex@npm:1.1.0" @@ -31814,6 +32047,22 @@ __metadata: languageName: node linkType: hard +"string.prototype.matchall@npm:^4.0.8": + version: 4.0.8 + resolution: "string.prototype.matchall@npm:4.0.8" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + get-intrinsic: ^1.1.3 + has-symbols: ^1.0.3 + internal-slot: ^1.0.3 + regexp.prototype.flags: ^1.4.3 + side-channel: ^1.0.4 + checksum: 644523d05c1ee93bab7474e999a5734ee5f6ad2d7ad24ed6ea8706c270dc92b352bde0f2a5420bfbeed54e28cb6a770c3800e1988a5267a70fd5e677c7750abc + languageName: node + linkType: hard + "string.prototype.padend@npm:^3.0.0": version: 3.1.3 resolution: "string.prototype.padend@npm:3.1.3" @@ -31847,6 +32096,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimend@npm:^1.0.6": + version: 1.0.6 + resolution: "string.prototype.trimend@npm:1.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 51b663e3195a74b58620a250b3fc4efb58951000f6e7d572a9f671c038f2f37f24a2b8c6994500a882aeab2f1c383fac1e8c023c01eb0c8b4e52d2f13b6c4513 + languageName: node + linkType: hard + "string.prototype.trimstart@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimstart@npm:1.0.5" @@ -31858,6 +32118,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.6": + version: 1.0.6 + resolution: "string.prototype.trimstart@npm:1.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 13b9970d4e234002dfc8069c655c1fe19e83e10ced208b54858c41bb0f7544e581ac0ce746e92b279563664ad63910039f7253f36942113fec413b2b4e7c1fcd + languageName: node + linkType: hard + "string_decoder@npm:^1.0.0, string_decoder@npm:^1.1.1": version: 1.3.0 resolution: "string_decoder@npm:1.3.0"