fix: Merge conflicts with master
This commit is contained in:
36
.github/workflows/docs-freshness-check.yml
vendored
Normal file
36
.github/workflows/docs-freshness-check.yml
vendored
Normal 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
|
||||
10
README.md
10
README.md
@@ -97,12 +97,12 @@ Write-ups for all features will be made available in [Github discussions](https
|
||||
- [x] Promotions API
|
||||
- [x] Price Lists API
|
||||
- [x] Price Selection Strategy
|
||||
- [ ] Import / Export API
|
||||
- [ ] Sales Channel API
|
||||
- [x] Import / Export 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 Order API (managing placed orders, improved inventory control, and more)
|
||||
- [ ] Multi-warehouse support
|
||||
- [ ] GraphQL API
|
||||
|
||||
## Plugins
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# Create a Batch Job Strategy
|
||||
|
||||
In this document, you’ll 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`:
|
||||
|
||||
<Tabs groupId="request-types">
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
// using JS Client
|
||||
medusa.admin.batchJobs.create({
|
||||
type: 'publish-products',
|
||||
context: { },
|
||||
@@ -263,8 +268,10 @@ medusa.admin.batchJobs.create({
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
// using Fetch API
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -282,8 +289,10 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
# using cURL
|
||||
curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs' \
|
||||
--header 'Authorization: Bearer <API_TOKEN>' \
|
||||
--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.
|
||||
|
||||
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:
|
||||
|
||||
<Tabs groupId="request-type">
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
// using JS Client
|
||||
medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
// using Fetch API
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`)
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
@@ -319,13 +335,18 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`)
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
# using cURL
|
||||
curl --location --request GET '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>' \
|
||||
--header 'Authorization: Bearer <API_TOKEN>'
|
||||
# <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:
|
||||
|
||||
```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):
|
||||
|
||||
<Tabs groupId="request-type">
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
// using JS Client
|
||||
medusa.admin.batchJobs.confirm(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
// using Fetch API
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
method: 'POST'
|
||||
})
|
||||
@@ -365,13 +390,18 @@ fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
# using cURL
|
||||
curl --location --request POST '<YOUR_SERVER>/admin/batch-jobs/<BATCH_JOB_ID>/confirm' \
|
||||
--header 'Authorization: Bearer <API_TOKEN>'
|
||||
# <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.
|
||||
|
||||
You can [retrieve the batch job](#optional-retrieve-batch-job) at any given point to check its status.
|
||||
|
||||
590
docs/content/advanced/backend/dependency-container/index.md
Normal file
590
docs/content/advanced/backend/dependency-container/index.md
Normal file
@@ -0,0 +1,590 @@
|
||||
# Dependency Container
|
||||
|
||||
In this document, you’ll 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 class’s 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 class’s constructor.
|
||||
|
||||
### Medusa’s 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 service’s constructor. That includes Medusa’s 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 Typeorm’s Entity Manager.
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
`manager`
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
Logger
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
An instance of Medusa CLI’s 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 flag’s value, or check if they’re 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 aren’t 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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What’s Next
|
||||
|
||||
- Learn [how to create services](../services/create-service.md).
|
||||
- Learn [how to create subscribers](../subscribers/create-subscriber.md).
|
||||
@@ -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.
|
||||
|
||||
Aside from Medusa’s 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 Medusa’s 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 [Typeorm’s Entities](https://typeorm.io/entities) and use Typeorm decorators.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ If you’re 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).
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -315,9 +315,13 @@ Please make sure that your plugin is following the correct structure. If the err
|
||||
```bash npm2yarn
|
||||
cd <SERVER_PATH>/node_modules/medusa-interfaces
|
||||
npm link
|
||||
cd <SERVER_PATH>/node_modules/@medusajs/medusa
|
||||
npm link
|
||||
cd <PLUGIN_PATH>
|
||||
rm -rf node_modules/medusa-interfaces
|
||||
rm -rf node_modules/@medusajs/medusa
|
||||
npm link medusa-interfaces
|
||||
npm link @medusajs/medusa
|
||||
npm link
|
||||
cd <SERVER_PATH>
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ For example, if you want to create a service `helloService`, create the file `he
|
||||
|
||||
```ts
|
||||
import { TransactionBaseService } from '@medusajs/medusa';
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
class HelloService extends TransactionBaseService {
|
||||
protected manager_: EntityManager;
|
||||
|
||||
@@ -8,13 +8,13 @@ Services in Medusa represent bundled helper methods that you want to use across
|
||||
|
||||
For example, you can use Medusa’s `productService` to get the list of products, as well as perform other functionalities related to products. There’s 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.
|
||||
|
||||
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 you’ll be referring to it when you want to get access to the service using dependency injection or in routes.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
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 subscriber’s 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.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Furthermore, your Medusa server should be configured to work with PostgreSQL and
|
||||
|
||||
### Required Tools
|
||||
|
||||
- Git’s 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).
|
||||
- Git’s 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).
|
||||
|
||||
## 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.
|
||||
|
||||
:::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:
|
||||
|
||||
:::note
|
||||
|
||||
This add-on is added with a free plan. However, Heroku might require you to add a payment method to proceed.
|
||||
|
||||
:::
|
||||
|
||||
```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
|
||||
|
||||
:::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:
|
||||
|
||||
:::note
|
||||
|
||||
This add-on is added with a free plan. However, Heroku might require you to add a payment method to proceed.
|
||||
|
||||
:::
|
||||
|
||||
```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
|
||||
|
||||
@@ -133,12 +115,12 @@ heroku buildpacks:set heroku/nodejs
|
||||
|
||||
#### 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
|
||||
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.
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# 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.
|
||||
@@ -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 cart’s data:
|
||||
|
||||
<Tabs groupId="request-type">
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
medusa.carts.update(cartId, {
|
||||
region_id
|
||||
@@ -175,6 +181,9 @@ medusa.carts.update(cartId, {
|
||||
.then(({ cart }) => setCart(cart));
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
@@ -189,6 +198,9 @@ fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
.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.
|
||||
|
||||
It returns the updated cart.
|
||||
|
||||
@@ -71,11 +71,13 @@
|
||||
"generate:entities": "typedoc --options typedoc.entities.js",
|
||||
"release:snapshot": "changeset publish --no-git-tags --snapshot --tag snapshot",
|
||||
"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": {
|
||||
"@changesets/changelog-github": "^0.4.5",
|
||||
"@changesets/cli": "^2.23.0",
|
||||
"@linear/sdk": "^1.22.0",
|
||||
"@octokit/core": "^4.0.5",
|
||||
"global": "^4.4.0",
|
||||
"import-from": "^3.0.0",
|
||||
|
||||
154
scripts/freshness-check.js
Normal file
154
scripts/freshness-check.js
Normal 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()
|
||||
@@ -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}
|
||||
{}
|
||||
@@ -388,6 +388,10 @@ module.exports = {
|
||||
type: "doc",
|
||||
id: "advanced/backend/customer-groups/index"
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "advanced/backend/dependency-container/index"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
23
yarn.lock
23
yarn.lock
@@ -2891,6 +2891,15 @@ __metadata:
|
||||
languageName: node
|
||||
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":
|
||||
version: 2.1.4
|
||||
resolution: "@hapi/address@npm:2.1.4"
|
||||
@@ -4165,6 +4174,17 @@ __metadata:
|
||||
languageName: node
|
||||
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":
|
||||
version: 2.5.2
|
||||
resolution: "@lmdb/lmdb-darwin-arm64@npm:2.5.2"
|
||||
@@ -18218,7 +18238,7 @@ __metadata:
|
||||
languageName: node
|
||||
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
|
||||
resolution: "graphql@npm:15.8.0"
|
||||
checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801
|
||||
@@ -30050,6 +30070,7 @@ __metadata:
|
||||
"@babel/runtime": ^7.11.2
|
||||
"@changesets/changelog-github": ^0.4.5
|
||||
"@changesets/cli": ^2.23.0
|
||||
"@linear/sdk": ^1.22.0
|
||||
"@octokit/core": ^4.0.5
|
||||
"@redocly/cli": latest
|
||||
"@typescript-eslint/eslint-plugin": ^5.36.2
|
||||
|
||||
Reference in New Issue
Block a user