fix: Merge conflicts with master

This commit is contained in:
olivermrbl
2022-10-21 14:21:06 +02:00
17 changed files with 887 additions and 51 deletions

View File

@@ -0,0 +1,36 @@
# Checks for outdated documentation content and sends notification about it
name: Docs Freshness Check
on:
schedule:
- cron: '0 0 1 * *' # once a month
jobs:
freshness-check:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.REFERENCE_PAT }}
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
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: Setup Node.js environment
uses: actions/setup-node@v2.4.1
with:
node-version: "14"
cache: "yarn"
- name: Install dependencies
uses: ./.github/actions/cache-deps
with:
extension: docs-freshness-check
- name: Perform Freshness Check
run: yarn check:freshness

View File

@@ -97,12 +97,12 @@ Write-ups for all features will be made available in [Github discussions](https
- [x] Promotions API - [x] Promotions API
- [x] Price Lists API - [x] Price Lists API
- [x] Price Selection Strategy - [x] Price Selection Strategy
- [ ] Import / Export API - [x] Import / Export API
- [ ] Sales Channel API - [x] Sales Channel API
- [ ] Extended Order API (managing placed orders)
- [ ] PaymentCollection API (collecting payments separate from carts and draft orders)
- [ ] Multi-warehouse API
- [ ] Extended Product API (custom fields, publishing control, and more) - [ ] Extended Product API (custom fields, publishing control, and more)
- [ ] Extended Order API (managing placed orders, improved inventory control, and more)
- [ ] Multi-warehouse support
- [ ] GraphQL API
## Plugins ## Plugins

View File

@@ -1,3 +1,6 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Create a Batch Job Strategy # Create a Batch Job Strategy
In this document, youll learn how to create a batch job strategy on your Medusa server. In this document, youll learn how to create a batch job strategy on your Medusa server.
@@ -251,8 +254,10 @@ The first step is to create a batch job using the [Create Batch Job endpoint](ht
For example, this creates a batch job of the type `publish-products`: For example, this creates a batch job of the type `publish-products`:
<Tabs groupId="request-types">
<TabItem value="client" label="Medusa JS Client" default>
```jsx ```jsx
// using JS Client
medusa.admin.batchJobs.create({ medusa.admin.batchJobs.create({
type: 'publish-products', type: 'publish-products',
context: { }, context: { },
@@ -263,8 +268,10 @@ medusa.admin.batchJobs.create({
}); });
``` ```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx ```jsx
// using Fetch API
fetch(`<YOUR_SERVER>/admin/batch-jobs`, { fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -282,8 +289,10 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
}); });
``` ```
</TabItem>
<TabItem value="curl" label="cURL">
```bash ```bash
# using cURL
curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs' \ curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs' \
--header 'Authorization: Bearer <API_TOKEN>' \ --header 'Authorization: Bearer <API_TOKEN>' \
--header 'Content-Type: application/json' \ --header 'Content-Type: application/json' \
@@ -294,6 +303,9 @@ curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs' \
}' }'
``` ```
</TabItem>
</Tabs>
You set the `dry_run` to `true` to disable automatic confirmation and running of the batch job. If you want the batch job to run automatically, you can remove this body parameter. You set the `dry_run` to `true` to disable automatic confirmation and running of the batch job. If you want the batch job to run automatically, you can remove this body parameter.
Make sure to replace `<YOUR_SERVER>` with the server URL where applicable. Make sure to replace `<YOUR_SERVER>` with the server URL where applicable.
@@ -302,16 +314,20 @@ Make sure to replace `<YOUR_SERVER>` with the server URL where applicable.
You can retrieve the batch job afterward to get its status and view details about the process in the `result` property: You can retrieve the batch job afterward to get its status and view details about the process in the `result` property:
<Tabs groupId="request-type">
<TabItem value="client" label="Medusa JS Client" default>
```jsx ```jsx
// using JS Client
medusa.admin.batchJobs.retrieve(batchJobId) medusa.admin.batchJobs.retrieve(batchJobId)
.then(( batch_job ) => { .then(( batch_job ) => {
console.log(batch_job.status, batch_job.result); console.log(batch_job.status, batch_job.result);
}); });
``` ```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx ```jsx
// using Fetch API
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`) fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`)
.then((response) => response.json()) .then((response) => response.json())
.then(({ batch_job }) => { .then(({ batch_job }) => {
@@ -319,13 +335,18 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`)
}); });
``` ```
</TabItem>
<TabItem value="curl" label="cURL">
```bash ```bash
# using cURL
curl --location --request GET '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>' \ curl --location --request GET '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>' \
--header 'Authorization: Bearer <API_TOKEN>' --header 'Authorization: Bearer <API_TOKEN>'
# <BATCH_JOB_ID> is the ID of the batch job # <BATCH_JOB_ID> is the ID of the batch job
``` ```
</TabItem>
</Tabs>
Based on the batch job strategy implemented in this documentation, the `result` property could be something like this: Based on the batch job strategy implemented in this documentation, the `result` property could be something like this:
```jsx ```jsx
@@ -346,16 +367,20 @@ Based on the batch job strategy implemented in this documentation, the `result`
To process the batch job, send a request to [confirm the batch job](https://docs.medusajs.com/api/admin/#tag/Batch-Job/operation/PostBatchJobsBatchJobConfirmProcessing): To process the batch job, send a request to [confirm the batch job](https://docs.medusajs.com/api/admin/#tag/Batch-Job/operation/PostBatchJobsBatchJobConfirmProcessing):
<Tabs groupId="request-type">
<TabItem value="client" label="Medusa JS Client" default>
```jsx ```jsx
// using JS Client
medusa.admin.batchJobs.confirm(batchJobId) medusa.admin.batchJobs.confirm(batchJobId)
.then(( batch_job ) => { .then(( batch_job ) => {
console.log(batch_job.status); console.log(batch_job.status);
}); });
``` ```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx ```jsx
// using Fetch API
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, { fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
method: 'POST' method: 'POST'
}) })
@@ -365,13 +390,18 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
}); });
``` ```
</TabItem>
<TabItem value="curl" label="cURL">
```bash ```bash
# using cURL
curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>/confirm' \ curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>/confirm' \
--header 'Authorization: Bearer <API_TOKEN>' --header 'Authorization: Bearer <API_TOKEN>'
# <BATCH_JOB_ID> is the ID of the batch job # <BATCH_JOB_ID> is the ID of the batch job
``` ```
</TabItem>
</Tabs>
The batch job will start processing afterward. Based on the batch job strategy implemented in this documentation, draft products will be published. The batch job will start processing afterward. Based on the batch job strategy implemented in this documentation, draft products will be published.
You can [retrieve the batch job](#optional-retrieve-batch-job) at any given point to check its status. You can [retrieve the batch job](#optional-retrieve-batch-job) at any given point to check its status.

View File

@@ -0,0 +1,590 @@
# Dependency Container
In this document, youll learn what the dependency container is and how you can use it in Medusa.
## Introduction
### What is Dependency Injection
Dependency Injection is the act of delivering the required resources to a class. These resources are the classs dependencies. This is usually done by passing (or injecting) the dependencies in the constructor of the class.
Generally, all resources are registered in a container. Then, whenever a class depends on one of these resources, the system retrieves the resources from the container and injects them into the classs constructor.
### Medusas Dependency Container
Medusa uses a dependency container to register essential resources of your server. You can then access these resources in classes and endpoints using the dependency container.
For example, if you create a custom service, you can access any other service registered in Medusa in your services constructor. That includes Medusas core services, services defined in plugins, or other services that you create on your server.
You can load more than services in your Medusa server. You can load the Entity Manager, logger instance, and much more.
### MedusaContainer
To manage dependency injections, Medusa uses [Awilix](https://github.com/jeffijoe/awilix). Awilix is an NPM package that implements dependency injection in Node.js projects.
When you run the Medusa server, a container of the type `MedusaContainer` is created. This type extends the [AwilixContainer](https://github.com/jeffijoe/awilix#the-awilixcontainer-object) object.
The server then registers all important resources in the container, which makes them accessible in classes and endpoints.
## Registered Resources
The Medusa server scans the core Medusa package, plugins, and your files in the `dist` directory and registers the following resources:
:::note
Many resources are registered under their camel-case name. These resources are formatted by taking the name of the file, transforming it to camel case, then appending the folder name to the name. So, the `services/product.ts` service is registered as `productService`.
:::
<table class="reference-table">
<thead>
<tr>
<th>
Resource
</th>
<th>
Description
</th>
<th>
Registration Name
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Configurations
</td>
<td>
The configurations that are exported from medusa-config.js.
</td>
<td>
`configModule`
</td>
</tr>
<tr>
<td>
Services
</td>
<td>
Services that extend the `TransactionBaseService` class.
</td>
<td>
Each service is registered under its camel-case name. For example, the `ProductService` is registered as `productService`.
</td>
</tr>
<tr>
<td>
Entity Manager
</td>
<td>
An instance of Typeorms Entity Manager.
</td>
<td>
`manager`
</td>
</tr>
<tr>
<td>
Logger
</td>
<td>
An instance of Medusa CLIs logger. You can use it to log messages to the terminal.
</td>
<td>
`logger`
</td>
</tr>
<tr>
<td>
Single Payment Provider
</td>
<td>
An instance of every payment provider that extends the `AbstractPaymentService` class.
</td>
<td>
Every payment provider is registered under two names:
- Its camel-case name. For example, the `StripeProviderService` is registered as `stripeProviderService`.
- `pp_` followed by its identifier. For example, the `StripeProviderService` is registered as `pp_stripe`.
</td>
</tr>
<tr>
<td>
All Payment Providers
</td>
<td>
An array of all payment providers that extend the `AbstractPaymentService` class.
</td>
<td>
`paymentProviders`
</td>
</tr>
<tr>
<td>
Single Fulfillment Provider
</td>
<td>
An instance of every fulfillment provider that extends the `FulfillmentService` class.
</td>
<td>
Every fulfillment provider is registered under two names:
- Its camel-case name. For example, the `WebshipperFulfillmentService` is registered as `webshipperFulfillmentService`.
- `fp_` followed by its identifier. For example, the `WebshipperFulfillmentService` is registered as `fp_webshipper`.
</td>
</tr>
<tr>
<td>
All Fulfillment Providers
</td>
<td>
An array of all fulfillment providers that extend the `FulfillmentService` class.
</td>
<td>
`fulfillmentProviders`
</td>
</tr>
<tr>
<td>
Single Notification Provider
</td>
<td>
An instance of every notification provider that extends the `AbstractNotificationService` or the `BaseNotificationService` classes.
</td>
<td>
Every notification provider is registered under two names:
- Its camel-case name. For example, the `SendGridService` is registered as `sendGridService`.
- `noti_` followed by its identifier. For example, the `SendGridService` is registered as `noti_sendgrid`.
</td>
</tr>
<tr>
<td>
All Notification Providers
</td>
<td>
An array of all notification providers that extend the `AbstractNotificationService` or the `BaseNotificationService` classes.
</td>
<td>
`notificationProviders`
</td>
</tr>
<tr>
<td>
File Service
</td>
<td>
An instance of the class that extends the `FileService` class, if any.
</td>
<td>
The file service is registered under two names:
- Its camel-case name. For example, the `MinioService` is registered as `minioService`.
- `fileService`
</td>
</tr>
<tr>
<td>
Search Service
</td>
<td>
An instance of the class that extends the `AbstractSearchService` or the `SearchService` classes, if any.
</td>
<td>
The search service is registered under two names:
- Its camel-case name. For example, the `AlgoliaService` is registered as `algoliaService`.
- `searchService`
</td>
</tr>
<tr>
<td>
Single Tax Provider
</td>
<td>
An instance of every tax provider that extends the `AbstractTaxService` class.
</td>
<td>
The tax provider is registered under two names:
- Its camel-case name.
- `tp_` followed by its identifier.
</td>
</tr>
<tr>
<td>
All Tax Providers
</td>
<td>
An array of every tax provider that extends the `AbstractTaxService` class.
</td>
<td>
`taxProviders`
</td>
</tr>
<tr>
<td>
Oauth Services
</td>
<td>
An instance of every service that extends the `OauthService` class.
</td>
<td>
Each Oauth Service is registered under its camel-case name followed by `Oauth`.
</td>
</tr>
<tr>
<td>
Feature Flag Router
</td>
<td>
An instance of the `FlagRouter`. This can be used to list feature flags, set a feature flags value, or check if theyre enabled.
</td>
<td>
`featureFlagRouter`
</td>
</tr>
<tr>
<td>
Redis
</td>
<td>
An instance of the Redis client. If Redis is not configured, a fake Redis client is registered.
</td>
<td>
`redisClient`
</td>
</tr>
<tr>
<td>
Single Entity
</td>
<td>
An instance of every entity.
</td>
<td>
Each entity is registered under its camel-case name followed by Model. For example, the `CustomerGroup` entity is stored under `customerGroupModel`.
</td>
</tr>
<tr>
<td>
All Entities
</td>
<td>
An array of all database entities that is passed to Typeorm when connecting to the database.
</td>
<td>
`db_entities`
</td>
</tr>
<tr>
<td>
Repositories
</td>
<td>
An instance of each repository.
</td>
<td>
Each repository is registered under its camel-case name. For example, `CustomerGroupRepository` is stored under `customerGroupRepository`.
</td>
</tr>
<tr>
<td>
Single Batch Job Strategy
</td>
<td>
An instance of every class extending the `AbstractBatchJobStrategy` class.
</td>
<td>
Each batch job strategy is registered under three names:
- Its camel-case name. For example, `ProductImportStrategy` is registered as `productImportStrategy`.
- `batch_` followed by its identifier. For example, the `ProductImportStrategy` is registered under `batch_product-import-strategy`.
- `batchType_` followed by its batch job type. For example, the `ProductImportStrategy` is registered under `batchType_product-import`.
</td>
</tr>
<tr>
<td>
All Batch Job Strategies
</td>
<td>
An array of all classes extending the `AbstractBatchJobStrategy` abstract class.
</td>
<td>
`batchJobStrategies`
</td>
</tr>
<tr>
<td>
Tax Calculation Strategy
</td>
<td>
An instance of the class implementing the `ITaxCalculationStrategy` interface.
</td>
<td>
`taxCalculationStrategy`
</td>
</tr>
<tr>
<td>
Cart Completion Strategy
</td>
<td>
An instance of the class extending the `AbstractCartCompletionStrategy` class.
</td>
<td>
`cartCompletionStrategy`
</td>
</tr>
<tr>
<td>
Price Selection Strategy
</td>
<td>
An instance of the class implementing the `IPriceSelectionStrategy` interface.
</td>
<td>
`priceSelectionStrategy`
</td>
</tr>
<tr>
<td>
Strategies
</td>
<td>
An instance of strategies that arent of the specific types mentioned above and that are under the `strategies` directory.
</td>
<td>
Its camel-case name.
</td>
</tr>
</tbody>
</table>
## Loading Resources
This section covers how to load resources that the Medusa server registers when it starts running.
### In Endpoints
To load resources, such as services, in endpoints, use the `req.scope.resolve` function. The function receives the registration name of the resource as a parameter.
For example:
```typescript
const logger = req.scope.resolve('logger');
```
Please note that in endpoints some resources, such as repositories, are not available.
### In Classes
In classes such as services, strategies, or subscribers, you can load resources in the constructor function. The constructor receives an object of dependencies as a first parameter. Each dependency in the object should use the registration name of the resource that should be injected to the class.
For example:
```typescript
import { OrderService } from '@medusajs/medusa';
class OrderSubscriber {
protected orderService: OrderService;
constructor({ orderService }) {
this.orderService = orderService;
}
}
```
## Whats Next
- Learn [how to create services](../services/create-service.md).
- Learn [how to create subscribers](../subscribers/create-subscriber.md).

View File

@@ -6,7 +6,7 @@ In this document, you'll learn what Entities are in Medusa.
Entities in medusa represent tables in the database as classes. An example of this would be the `Order` entity which represents the `order` table in the database. Entities provide a uniform way of defining and interacting with data retrieved from the database. Entities in medusa represent tables in the database as classes. An example of this would be the `Order` entity which represents the `order` table in the database. Entities provide a uniform way of defining and interacting with data retrieved from the database.
Aside from Medusas core entities, you can also create your own entities to use in your Medusa server. Custom entities must reside in the `src/models` directory of your Medusa server. Aside from Medusas core entities, you can also create your own entities to use in your Medusa server. Custom entities are TypeScript or JavaScript files located in the `src/models` directory of your Medusa server.
Entities are TypeScript files and they are based on [Typeorms Entities](https://typeorm.io/entities) and use Typeorm decorators. Entities are TypeScript files and they are based on [Typeorms Entities](https://typeorm.io/entities) and use Typeorm decorators.

View File

@@ -12,7 +12,7 @@ If youre unfamiliar with the Notification architecture in Medusa, it is recom
Before you start creating a Notification Provider, you need to install a [Medusa server](../../../quickstart/quick-start.md). Before you start creating a Notification Provider, you need to install a [Medusa server](../../../quickstart/quick-start.md).
You also need to (../../../tutorial/0-set-up-your-development-environment.mdx#redis) and [configure it with the Medusa server](../../../usage/configurations.md#redis). You also need to [setup Redis](../../../tutorial/0-set-up-your-development-environment.mdx#redis) and [configure it with the Medusa server](../../../usage/configurations.md#redis).
## Create a Notification Provider ## Create a Notification Provider

View File

@@ -315,9 +315,13 @@ Please make sure that your plugin is following the correct structure. If the err
```bash npm2yarn ```bash npm2yarn
cd <SERVER_PATH>/node_modules/medusa-interfaces cd <SERVER_PATH>/node_modules/medusa-interfaces
npm link npm link
cd <SERVER_PATH>/node_modules/@medusajs/medusa
npm link
cd <PLUGIN_PATH> cd <PLUGIN_PATH>
rm -rf node_modules/medusa-interfaces rm -rf node_modules/medusa-interfaces
rm -rf node_modules/@medusajs/medusa
npm link medusa-interfaces npm link medusa-interfaces
npm link @medusajs/medusa
npm link npm link
cd <SERVER_PATH> cd <SERVER_PATH>
npm link your-plugin npm link your-plugin
@@ -325,7 +329,7 @@ npm link your-plugin
Where `<SERVER_PATH>` is the path to your Medusa server and `<PLUGIN_PATH>` is the path to your plugin. Where `<SERVER_PATH>` is the path to your Medusa server and `<PLUGIN_PATH>` is the path to your plugin.
This links the `medusa-interfaces` package from your `medusa-backend` to your plugin directory and then links your plugin to your `medusa-backend`. This links the `medusa-interfaces` and `@medusajs/medusa` packages from your `medusa-backend` to your plugin directory and then links your plugin to your `medusa-backend`.
#### APIs not loading #### APIs not loading

View File

@@ -10,6 +10,7 @@ For example, if you want to create a service `helloService`, create the file `he
```ts ```ts
import { TransactionBaseService } from '@medusajs/medusa'; import { TransactionBaseService } from '@medusajs/medusa';
import { EntityManager } from 'typeorm';
class HelloService extends TransactionBaseService { class HelloService extends TransactionBaseService {
protected manager_: EntityManager; protected manager_: EntityManager;

View File

@@ -8,13 +8,13 @@ Services in Medusa represent bundled helper methods that you want to use across
For example, you can use Medusas `productService` to get the list of products, as well as perform other functionalities related to products. Theres also an `authService` that provides functionalities like authenticating customers and users. For example, you can use Medusas `productService` to get the list of products, as well as perform other functionalities related to products. Theres also an `authService` that provides functionalities like authenticating customers and users.
Custom services reside in the `src/services` directory of your Medusa Server installation. Each service should be a class that extends the `TransactionBaseService` class from the core Medusa package `@medusajs/medusa`. Custom services are TypeScript or JavaScript files located in the `src/services` directory of your Medusa Server installation. Each service should be a class that extends the `TransactionBaseService` class from the core Medusa package `@medusajs/medusa`.
Each file you create in `src/services` should hold one service and export it. Each file you create in `src/services` should hold one service and export it.
The file name is important as it determines the name of the service when you need to use it elsewhere. The name of the service will be registered as the camel-case version of the file name + `Service` at the end of the name. The file name is important as it determines the name of the service when you need to use it elsewhere. The name of the service will be registered as the camel-case version of the file name + `Service` at the end of the name.
For example, if the file name is `hello.js`, the service will be registered as `helloService`. If the file name is `hello-world.js`, the service name will be registered as `helloWorldService`. For example, if the file name is `hello.ts`, the service will be registered as `helloService`. If the file name is `hello-world.ts`, the service name will be registered as `helloWorldService`.
The registration name of the service is important, as youll be referring to it when you want to get access to the service using dependency injection or in routes. The registration name of the service is important, as youll be referring to it when you want to get access to the service using dependency injection or in routes.

View File

@@ -16,7 +16,7 @@ Subscribers register handlers for an events and allows you to perform an action
Natively in Medusa there are subscribers to handle different events. However, you can also create your own custom subscribers. Natively in Medusa there are subscribers to handle different events. However, you can also create your own custom subscribers.
Custom subscribers reside in your project's `src/subscribers` directory. Files here should export classes, which will be treated as subscribers by Medusa. By convention, the class name should end with `Subscriber` and the file name should be the camel-case version of the class name without `Subscriber`. For example, the `WelcomeSubscriber` class is in the file `src/subscribers/welcome.js`. Custom subscribers are TypeScript or JavaScript files in your project's `src/subscribers` directory. Files here should export classes, which will be treated as subscribers by Medusa. By convention, the class name should end with `Subscriber` and the file name should be the camel-case version of the class name without `Subscriber`. For example, the `WelcomeSubscriber` class is in the file `src/subscribers/welcome.ts`.
Whenever an event is emitted, the subscribers registered handler method is executed. The handler method receives as a parameter an object that holds data related to the event. For example, if an order is placed the `order.placed` event will be emitted and all the handlers will receive the order id in the parameter object. Whenever an event is emitted, the subscribers registered handler method is executed. The handler method receives as a parameter an object that holds data related to the event. For example, if an order is placed the `order.placed` event will be emitted and all the handlers will receive the order id in the parameter object.

View File

@@ -30,7 +30,7 @@ Furthermore, your Medusa server should be configured to work with PostgreSQL and
### Required Tools ### Required Tools
- Gits CLI tool. You can follow [this documentation to learn how to install it for your operating system](../../tutorial/0-set-up-your-development-environment.mdx#git). - Gits CLI tool. You can follow [this documentation to learn how to install it for your operating system](../../tutorial/0-set-up-your-development-environment.mdx#git).
- Heroku's CLI tool. You can follow [Heroku's documentation to learn how to install it for your operating system](https://devcenter.heroku.com/articles/heroku-cli). - Heroku's CLI tool. You can follow [Heroku's documentation to learn how to install it for your operating system](https://devcenter.heroku.com/articles/heroku-cli).
## Deploy to Heroku ## Deploy to Heroku
@@ -60,9 +60,9 @@ Where `<APP_NAME>` is the name of the app you'll create. You can use any name yo
Medusa requires a Postgres database and a Redis instance to work. You can add those to your Heroku app using Add-ons. Medusa requires a Postgres database and a Redis instance to work. You can add those to your Heroku app using Add-ons.
:::tip :::note
In this section, the add-ons are used with a free plan. It's highly recommended that you don't use a free plan in a production environment. If you don't have a payment method set up in your Heroku account, you'll be asked to enter your payment details when you try to install these addons.
::: :::
@@ -70,39 +70,21 @@ In this section, the add-ons are used with a free plan. It's highly recommended
Add a Postgres add-on to your Heroku app with the following command: Add a Postgres add-on to your Heroku app with the following command:
:::note
This add-on is added with a free plan. However, Heroku might require you to add a payment method to proceed.
:::
```bash ```bash
heroku addons:create heroku-postgresql:hobby-dev heroku addons:create heroku-postgresql:hobby-basic
``` ```
This uses the free plan of Heroku Postgres. Make sure to check out [more information regarding the plans and pricing of Heroku Postgres](https://elements.heroku.com/addons/heroku-postgresql#pricing). This uses Heroku Postgres's basic plan. You can check out [the available plans and pricing of Heroku Postgres on Heroku's website.](https://elements.heroku.com/addons/heroku-postgresql#pricing)
#### Redis #### Redis
:::note
The Add-on used here for Redis is [Upstash](https://devcenter.heroku.com/articles/upstash-redis) which is currently in beta. However, it provides a generous free plan. You can alternatively go for [Stackhero](https://elements.heroku.com/addons/stackhero-redis) but it does not have a free plan.
:::
Add a Redis instance to your Heroku app with the following command: Add a Redis instance to your Heroku app with the following command:
:::note
This add-on is added with a free plan. However, Heroku might require you to add a payment method to proceed.
:::
```bash ```bash
heroku addons:create upstash-redis heroku addons:create stackhero-redis:ist-ebi1rc
``` ```
This uses the free plan of Upstash. Make sure to check out [more information regarding the plans and pricing of Upstash](https://elements.heroku.com/addons/upstash-redis#pricing). This uses the lowest plan in Stackhero Redis. You can check out [the plans and pricing of Stackhero Redis on Heroku's website.](https://elements.heroku.com/addons/stackhero-redis#pricing)
### 4. Configure Environment Variables on Heroku ### 4. Configure Environment Variables on Heroku
@@ -133,12 +115,12 @@ heroku buildpacks:set heroku/nodejs
#### Configure the Redis URL #### Configure the Redis URL
Upstash adds the Redis URL under the environment variable `UPSTASH_REDIS_URL`. However, Medusa looks for the `REDIS_URL` environment variable when initializing the connection with Redis. Stackhero Redis adds the Redis URL under the environment variable `STACKHERO_REDIS_URL_TLS`. However, Medusa looks for the `REDIS_URL` environment variable when initializing the connection with Redis.
Retrieve the value of `UPSTASH_REDIS_URL` with the following command: Retrieve the value of `STACKHERO_REDIS_URL_TLS` with the following command:
```bash ```bash
heroku config:get UPSTASH_REDIS_URL heroku config:get STACKHERO_REDIS_URL_TLS
``` ```
This prints the value of the environment variable which is a Redis connection string. This prints the value of the environment variable which is a Redis connection string.

View File

@@ -1,3 +1,6 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# How to Add Cart Functionality # How to Add Cart Functionality
This document guides you through how you can add cart-related functionalities to your storefront. That includes creating and updating a cart and managing items in the cart. This document guides you through how you can add cart-related functionalities to your storefront. That includes creating and updating a cart and managing items in the cart.
@@ -168,6 +171,9 @@ A cart has different data associated with it including the region, email, addres
You can use the following snippet to update any of the carts data: You can use the following snippet to update any of the carts data:
<Tabs groupId="request-type">
<TabItem value="client" label="Medusa JS Client" default>
```jsx ```jsx
medusa.carts.update(cartId, { medusa.carts.update(cartId, {
region_id region_id
@@ -175,6 +181,9 @@ medusa.carts.update(cartId, {
.then(({ cart }) => setCart(cart)); .then(({ cart }) => setCart(cart));
``` ```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```jsx ```jsx
fetch(`<SERVER_URL>/store/carts/${cartId}`, { fetch(`<SERVER_URL>/store/carts/${cartId}`, {
method: 'POST', method: 'POST',
@@ -189,6 +198,9 @@ fetch(`<SERVER_URL>/store/carts/${cartId}`, {
.then(({ cart }) => setCart(cart)); .then(({ cart }) => setCart(cart));
``` ```
</TabItem>
</Tabs>
This request accepts the ID of the cart as a path parameter. In its body, you can pass any data you want to update in the cart such as the region. This request accepts the ID of the cart as a path parameter. In its body, you can pass any data you want to update in the cart such as the region.
It returns the updated cart. It returns the updated cart.

View File

@@ -71,11 +71,13 @@
"generate:entities": "typedoc --options typedoc.entities.js", "generate:entities": "typedoc --options typedoc.entities.js",
"release:snapshot": "changeset publish --no-git-tags --snapshot --tag snapshot", "release:snapshot": "changeset publish --no-git-tags --snapshot --tag snapshot",
"generate:announcement": "node ./scripts/doc-change-release.js", "generate:announcement": "node ./scripts/doc-change-release.js",
"version:staging": "yarn changeset pre enter staging && yarn changeset version" "version:staging": "yarn changeset pre enter staging && yarn changeset version",
"check:freshness": "node ./scripts/freshness-check.js"
}, },
"dependencies": { "dependencies": {
"@changesets/changelog-github": "^0.4.5", "@changesets/changelog-github": "^0.4.5",
"@changesets/cli": "^2.23.0", "@changesets/cli": "^2.23.0",
"@linear/sdk": "^1.22.0",
"@octokit/core": "^4.0.5", "@octokit/core": "^4.0.5",
"global": "^4.4.0", "global": "^4.4.0",
"import-from": "^3.0.0", "import-from": "^3.0.0",

154
scripts/freshness-check.js Normal file
View File

@@ -0,0 +1,154 @@
#!/usr/bin/env node
const { LinearClient } = require("@linear/sdk");
const { Octokit } = require("@octokit/core");
const fs = require('fs');
const path = require('path');
const octokit = new Octokit({
auth: process.env.GH_TOKEN
});
const linearClient = new LinearClient({
apiKey: process.env.LINEAR_API_KEY
});
const repoPath = path.join('docs', 'content');
let freshnessCheckLabelId = "";
let documentationTeamId = "";
async function scanDirectory (startPath) {
const files = fs.readdirSync(path.join(startPath), {
withFileTypes: true
});
for (const file of files) {
const filePath = path.join(startPath, file.name);
if (file.isDirectory()) {
//if it's references directory, skip
if (file.name !== 'references' && file.name !== 'upgrade-guides') {
await scanDirectory(filePath);
}
continue;
}
//check that the file is a markdown file
if (file.name.indexOf('.md') === -1 && file.name.indexOf('.mdx') === -1 ) {
continue;
}
//if it is a file, check its commits in GitHub
const commitResponse = await octokit.request('GET /repos/{owner}/{repo}/commits', {
owner: 'medusajs',
repo: 'medusa',
path: filePath,
per_page: 1
})
if (!commitResponse.data.length) {
continue;
}
const today = new Date();
const lastEditedDate = new Date(commitResponse.data[0].commit.committer.date);
const monthsSinceEdited = getMonthDifference(lastEditedDate, today);
if (monthsSinceEdited > 6) {
//file was edited more than 6 months ago.
//check if there's an issue created for this file since the commit date
const existingIssue = await linearClient.issues({
filter: {
createdAt: {
gte: subtractMonths(monthsSinceEdited - 6, today)
},
title: {
containsIgnoreCase: `Freshness check for ${filePath}`
},
labels: {
some: {
id: {
eq: freshnessCheckLabelId
}
}
}
},
first: 1
});
if (existingIssue.nodes.length) {
//an issue has been created for the past 6 months. Don't create an issue for it.
continue;
}
console.log(`Creating an issue for ${filePath}...`);
//there are no issues in the past 6 months. Create an issue
await linearClient.issueCreate({
teamId: documentationTeamId,
title: `Freshness check for ${filePath}`,
labelIds: [
freshnessCheckLabelId
],
description: `File \`${filePath}\` was last edited on ${lastEditedDate.toDateString()}.`
})
}
}
}
async function main () {
//fetch documentation team ID from linear
const documentationTeam = await linearClient.teams({
filter: {
name: {
eqIgnoreCase: 'Documentation'
}
},
first: 1
});
if (!documentationTeam.nodes.length) {
console.log("Please add Documentation team in Linear first then try again");
process.exit(1);
}
documentationTeamId = documentationTeam.nodes[0].id;
//fetch freshness check label ID from linear
const freshnessCheckLabel = await linearClient.issueLabels({
filter: {
name: {
eqIgnoreCase: 'type: freshness-check'
},
team: {
id: {
eq: documentationTeamId
}
}
}
});
if (!freshnessCheckLabel.nodes.length) {
console.log("Please add freshness check label in Linear under the documentation team first then try again");
process.exit(1);
}
freshnessCheckLabelId = freshnessCheckLabel.nodes[0].id;
await scanDirectory(repoPath);
}
function getMonthDifference(startDate, endDate) {
return (
endDate.getMonth() -
startDate.getMonth() +
12 * (endDate.getFullYear() - startDate.getFullYear())
);
}
function subtractMonths(numOfMonths, date = new Date()) {
date.setMonth(date.getMonth() - numOfMonths);
return date;
}
main()

View File

@@ -1 +1 @@
{"id":"release-v1-5-0","content":"New Release! Version v1.5.0 of Medusa is out now! Read all about it <a href='https://github.com/medusajs/medusa/releases/tag/v1.5.0'>here</a>.","backgroundColor":"#7C53FF","textColor":"#fff","isCloseable":false} {}

View File

@@ -388,6 +388,10 @@ module.exports = {
type: "doc", type: "doc",
id: "advanced/backend/customer-groups/index" id: "advanced/backend/customer-groups/index"
}, },
{
type: "doc",
id: "advanced/backend/dependency-container/index"
},
] ]
}, },
{ {

View File

@@ -2891,6 +2891,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@graphql-typed-document-node/core@npm:^3.1.0":
version: 3.1.1
resolution: "@graphql-typed-document-node/core@npm:3.1.1"
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
checksum: c186e5adceb0dfdaa770856d2f17c831a474f5927d79f984326ecb3d8680ba3c1ee2314f7def1d863692cd9cbe4dffc8bb52fc74ee0aa9b31e9491f24ef59f90
languageName: node
linkType: hard
"@hapi/address@npm:^2.1.2": "@hapi/address@npm:^2.1.2":
version: 2.1.4 version: 2.1.4
resolution: "@hapi/address@npm:2.1.4" resolution: "@hapi/address@npm:2.1.4"
@@ -4165,6 +4174,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@linear/sdk@npm:^1.22.0":
version: 1.22.0
resolution: "@linear/sdk@npm:1.22.0"
dependencies:
"@graphql-typed-document-node/core": ^3.1.0
graphql: ^15.4.0
isomorphic-unfetch: ^3.1.0
checksum: 7e8f24f617631d027fd606334a498b04014d4c33603bcb3e08073d14f86260d116597983567f8bc147a935e4557180158175b52b9a9a8a270a234b946894a82b
languageName: node
linkType: hard
"@lmdb/lmdb-darwin-arm64@npm:2.5.2": "@lmdb/lmdb-darwin-arm64@npm:2.5.2":
version: 2.5.2 version: 2.5.2
resolution: "@lmdb/lmdb-darwin-arm64@npm:2.5.2" resolution: "@lmdb/lmdb-darwin-arm64@npm:2.5.2"
@@ -18218,7 +18238,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"graphql@npm:^15.5.1, graphql@npm:^15.7.2": "graphql@npm:^15.4.0, graphql@npm:^15.5.1, graphql@npm:^15.7.2":
version: 15.8.0 version: 15.8.0
resolution: "graphql@npm:15.8.0" resolution: "graphql@npm:15.8.0"
checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801 checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801
@@ -30050,6 +30070,7 @@ __metadata:
"@babel/runtime": ^7.11.2 "@babel/runtime": ^7.11.2
"@changesets/changelog-github": ^0.4.5 "@changesets/changelog-github": ^0.4.5
"@changesets/cli": ^2.23.0 "@changesets/cli": ^2.23.0
"@linear/sdk": ^1.22.0
"@octokit/core": ^4.0.5 "@octokit/core": ^4.0.5
"@redocly/cli": latest "@redocly/cli": latest
"@typescript-eslint/eslint-plugin": ^5.36.2 "@typescript-eslint/eslint-plugin": ^5.36.2