mercur-cli 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/backend-setup.js +2 -2
- package/cli/data.js +3 -0
- package/cli/frontend-setup.js +17 -0
- package/cli/full-install.js +7 -1
- package/cli/pull-and-install.js +13 -1
- package/cli/start.js +14 -1
- package/index.js +5 -0
- package/package.json +1 -1
- package/mercur/backend/.env.template +0 -8
- package/mercur/backend/.env.test +0 -0
- package/mercur/backend/.github/dependabot.yml +0 -21
- package/mercur/backend/.github/scripts/wait-for-server-live.sh +0 -29
- package/mercur/backend/.github/workflows/test-cli.yml +0 -222
- package/mercur/backend/.github/workflows/update-preview-deps-ci.yml +0 -69
- package/mercur/backend/.github/workflows/update-preview-deps.yml +0 -67
- package/mercur/backend/.vscode/settings.json +0 -2
- package/mercur/backend/.yarnrc.yml +0 -1
- package/mercur/backend/README.md +0 -62
- package/mercur/backend/instrumentation.ts +0 -24
- package/mercur/backend/integration-tests/http/README.md +0 -29
- package/mercur/backend/integration-tests/http/health.spec.ts +0 -15
- package/mercur/backend/integration-tests/setup.js +0 -3
- package/mercur/backend/jest.config.js +0 -27
- package/mercur/backend/medusa-config.ts +0 -88
- package/mercur/backend/package.json +0 -65
- package/mercur/backend/src/admin/README.md +0 -33
- package/mercur/backend/src/admin/tsconfig.json +0 -24
- package/mercur/backend/src/admin/vite-env.d.ts +0 -1
- package/mercur/backend/src/api/README.md +0 -135
- package/mercur/backend/src/api/admin/custom/route.ts +0 -8
- package/mercur/backend/src/api/store/custom/route.ts +0 -8
- package/mercur/backend/src/jobs/README.md +0 -38
- package/mercur/backend/src/links/README.md +0 -26
- package/mercur/backend/src/modules/README.md +0 -117
- package/mercur/backend/src/scripts/README.md +0 -63
- package/mercur/backend/src/scripts/seed/seed-functions.ts +0 -519
- package/mercur/backend/src/scripts/seed/seed-products.ts +0 -601
- package/mercur/backend/src/scripts/seed.ts +0 -75
- package/mercur/backend/src/subscribers/README.md +0 -61
- package/mercur/backend/src/workflows/README.md +0 -81
- package/mercur/backend/tsconfig.json +0 -35
- package/mercur/backend/yarn.lock +0 -11469
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Integration Tests
|
|
2
|
-
|
|
3
|
-
The `medusa-test-utils` package provides utility functions to create integration tests for your API routes and workflows.
|
|
4
|
-
|
|
5
|
-
For example:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
|
9
|
-
|
|
10
|
-
medusaIntegrationTestRunner({
|
|
11
|
-
testSuite: ({ api, getContainer }) => {
|
|
12
|
-
describe("Custom endpoints", () => {
|
|
13
|
-
describe("GET /store/custom", () => {
|
|
14
|
-
it("returns correct message", async () => {
|
|
15
|
-
const response = await api.get(
|
|
16
|
-
`/store/custom`
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
expect(response.status).toEqual(200)
|
|
20
|
-
expect(response.data).toHaveProperty("message")
|
|
21
|
-
expect(response.data.message).toEqual("Hello, World!")
|
|
22
|
-
})
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Learn more in [this documentation](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/integration-tests).
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
|
2
|
-
jest.setTimeout(60 * 1000)
|
|
3
|
-
|
|
4
|
-
medusaIntegrationTestRunner({
|
|
5
|
-
inApp: true,
|
|
6
|
-
env: {},
|
|
7
|
-
testSuite: ({ api }) => {
|
|
8
|
-
describe("Ping", () => {
|
|
9
|
-
it("ping the server health endpoint", async () => {
|
|
10
|
-
const response = await api.get('/health')
|
|
11
|
-
expect(response.status).toEqual(200)
|
|
12
|
-
})
|
|
13
|
-
})
|
|
14
|
-
},
|
|
15
|
-
})
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const { loadEnv } = require("@medusajs/utils");
|
|
2
|
-
loadEnv("test", process.cwd());
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
transform: {
|
|
6
|
-
"^.+\\.[jt]s$": [
|
|
7
|
-
"@swc/jest",
|
|
8
|
-
{
|
|
9
|
-
jsc: {
|
|
10
|
-
parser: { syntax: "typescript", decorators: true },
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
|
-
testEnvironment: "node",
|
|
16
|
-
moduleFileExtensions: ["js", "ts", "json"],
|
|
17
|
-
modulePathIgnorePatterns: ["dist/", "<rootDir>/.medusa/"],
|
|
18
|
-
setupFiles: ["./integration-tests/setup.js"],
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
if (process.env.TEST_TYPE === "integration:http") {
|
|
22
|
-
module.exports.testMatch = ["**/integration-tests/http/*.spec.[jt]s"];
|
|
23
|
-
} else if (process.env.TEST_TYPE === "integration:modules") {
|
|
24
|
-
module.exports.testMatch = ["**/src/modules/*/__tests__/**/*.[jt]s"];
|
|
25
|
-
} else if (process.env.TEST_TYPE === "unit") {
|
|
26
|
-
module.exports.testMatch = ["**/src/**/__tests__/**/*.unit.spec.[jt]s"];
|
|
27
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { defineConfig, loadEnv } from '@medusajs/framework/utils'
|
|
3
|
-
|
|
4
|
-
loadEnv(process.env.NODE_ENV || 'development', process.cwd())
|
|
5
|
-
|
|
6
|
-
module.exports = defineConfig({
|
|
7
|
-
projectConfig: {
|
|
8
|
-
databaseUrl: process.env.DATABASE_URL,
|
|
9
|
-
http: {
|
|
10
|
-
storeCors: process.env.STORE_CORS!,
|
|
11
|
-
adminCors: process.env.ADMIN_CORS!,
|
|
12
|
-
// @ts-expect-error: vendorCors is not a valid config
|
|
13
|
-
vendorCors: process.env.VENDOR_CORS!,
|
|
14
|
-
authCors: process.env.AUTH_CORS!,
|
|
15
|
-
jwtSecret: process.env.JWT_SECRET || 'supersecret',
|
|
16
|
-
cookieSecret: process.env.COOKIE_SECRET || 'supersecret'
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
plugins: [
|
|
20
|
-
{
|
|
21
|
-
resolve: '@mercurjs/b2c-core',
|
|
22
|
-
options: {}
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
resolve: '@mercurjs/commission',
|
|
26
|
-
options: {}
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
resolve: '@mercurjs/algolia',
|
|
30
|
-
options: {
|
|
31
|
-
apiKey: process.env.ALGOLIA_API_KEY,
|
|
32
|
-
appId: process.env.ALGOLIA_APP_ID
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
resolve: '@mercurjs/reviews',
|
|
37
|
-
options: {}
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
resolve: '@mercurjs/requests',
|
|
41
|
-
options: {}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
resolve: '@mercurjs/resend',
|
|
45
|
-
options: {}
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
modules: [
|
|
49
|
-
{
|
|
50
|
-
resolve: '@medusajs/medusa/payment',
|
|
51
|
-
options: {
|
|
52
|
-
providers: [
|
|
53
|
-
{
|
|
54
|
-
resolve:
|
|
55
|
-
'@mercurjs/payment-stripe-connect/providers/stripe-connect',
|
|
56
|
-
id: 'stripe-connect',
|
|
57
|
-
options: {
|
|
58
|
-
apiKey: process.env.STRIPE_SECRET_API_KEY
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
resolve: '@medusajs/medusa/notification',
|
|
66
|
-
options: {
|
|
67
|
-
providers: [
|
|
68
|
-
{
|
|
69
|
-
resolve: '@mercurjs/resend/providers/resend',
|
|
70
|
-
id: 'resend',
|
|
71
|
-
options: {
|
|
72
|
-
channels: ['email'],
|
|
73
|
-
api_key: process.env.RESEND_API_KEY,
|
|
74
|
-
from: process.env.RESEND_FROM_EMAIL
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
resolve: '@medusajs/medusa/notification-local',
|
|
79
|
-
id: 'local',
|
|
80
|
-
options: {
|
|
81
|
-
channels: ['feed', 'seller_feed']
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
})
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "medusa-starter-default",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"description": "A starter for Medusa projects.",
|
|
5
|
-
"author": "Medusa (https://medusajs.com)",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"sqlite",
|
|
9
|
-
"postgres",
|
|
10
|
-
"typescript",
|
|
11
|
-
"ecommerce",
|
|
12
|
-
"headless",
|
|
13
|
-
"medusa"
|
|
14
|
-
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "medusa build",
|
|
17
|
-
"seed": "medusa exec ./src/scripts/seed.ts",
|
|
18
|
-
"start": "medusa start",
|
|
19
|
-
"dev": "medusa develop",
|
|
20
|
-
"test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
|
|
21
|
-
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
|
|
22
|
-
"test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"@medusajs/admin-sdk": "2.10.3",
|
|
26
|
-
"@medusajs/cli": "2.10.3",
|
|
27
|
-
"@medusajs/framework": "2.10.3",
|
|
28
|
-
"@medusajs/medusa": "2.10.3",
|
|
29
|
-
"@mercurjs/algolia": "^1.3.0",
|
|
30
|
-
"@mercurjs/b2c-core": "^1.3.0",
|
|
31
|
-
"@mercurjs/commission": "^1.3.0",
|
|
32
|
-
"@mercurjs/framework": "^1.3.0",
|
|
33
|
-
"@mercurjs/payment-stripe-connect": "^1.3.0",
|
|
34
|
-
"@mercurjs/requests": "^1.3.0",
|
|
35
|
-
"@mercurjs/resend": "^1.3.0",
|
|
36
|
-
"@mercurjs/reviews": "^1.3.0",
|
|
37
|
-
"@mikro-orm/core": "6.4.3",
|
|
38
|
-
"@mikro-orm/knex": "6.4.3",
|
|
39
|
-
"@mikro-orm/migrations": "6.4.3",
|
|
40
|
-
"@mikro-orm/postgresql": "6.4.3",
|
|
41
|
-
"awilix": "^8.0.1",
|
|
42
|
-
"pg": "^8.13.0"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@medusajs/test-utils": "2.10.3",
|
|
46
|
-
"@mikro-orm/cli": "6.4.3",
|
|
47
|
-
"@swc/core": "1.5.7",
|
|
48
|
-
"@swc/jest": "^0.2.36",
|
|
49
|
-
"@types/jest": "^29.5.13",
|
|
50
|
-
"@types/node": "^20.0.0",
|
|
51
|
-
"@types/react": "^18.3.2",
|
|
52
|
-
"@types/react-dom": "^18.2.25",
|
|
53
|
-
"jest": "^29.7.0",
|
|
54
|
-
"prop-types": "^15.8.1",
|
|
55
|
-
"react": "^18.2.0",
|
|
56
|
-
"react-dom": "^18.2.0",
|
|
57
|
-
"ts-node": "^10.9.2",
|
|
58
|
-
"typescript": "^5.6.2",
|
|
59
|
-
"vite": "^5.2.11",
|
|
60
|
-
"yalc": "^1.0.0-pre.53"
|
|
61
|
-
},
|
|
62
|
-
"engines": {
|
|
63
|
-
"node": ">=20"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Admin Customizations
|
|
2
|
-
|
|
3
|
-
You can extend the Medusa Admin to add widgets and new pages. Your customizations interact with API routes to provide merchants with custom functionalities.
|
|
4
|
-
|
|
5
|
-
> Learn more about Admin Extensions in [this documentation](https://docs.medusajs.com/learn/fundamentals/admin).
|
|
6
|
-
|
|
7
|
-
## Example: Create a Widget
|
|
8
|
-
|
|
9
|
-
A widget is a React component that can be injected into an existing page in the admin dashboard.
|
|
10
|
-
|
|
11
|
-
For example, create the file `src/admin/widgets/product-widget.tsx` with the following content:
|
|
12
|
-
|
|
13
|
-
```tsx title="src/admin/widgets/product-widget.tsx"
|
|
14
|
-
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
|
15
|
-
|
|
16
|
-
// The widget
|
|
17
|
-
const ProductWidget = () => {
|
|
18
|
-
return (
|
|
19
|
-
<div>
|
|
20
|
-
<h2>Product Widget</h2>
|
|
21
|
-
</div>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// The widget's configurations
|
|
26
|
-
export const config = defineWidgetConfig({
|
|
27
|
-
zone: "product.details.after",
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
export default ProductWidget
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
This inserts a widget with the text “Product Widget” at the end of a product’s details page.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
|
|
9
|
-
/* Bundler mode */
|
|
10
|
-
"moduleResolution": "bundler",
|
|
11
|
-
"allowImportingTsExtensions": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"jsx": "react-jsx",
|
|
16
|
-
|
|
17
|
-
/* Linting */
|
|
18
|
-
"strict": true,
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"noFallthroughCasesInSwitch": true
|
|
22
|
-
},
|
|
23
|
-
"include": ["."]
|
|
24
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Custom API Routes
|
|
2
|
-
|
|
3
|
-
An API Route is a REST API endpoint.
|
|
4
|
-
|
|
5
|
-
An API Route is created in a TypeScript or JavaScript file under the `/src/api` directory of your Medusa application. The file’s name must be `route.ts` or `route.js`.
|
|
6
|
-
|
|
7
|
-
> Learn more about API Routes in [this documentation](https://docs.medusajs.com/learn/fundamentals/api-routes)
|
|
8
|
-
|
|
9
|
-
For example, to create a `GET` API Route at `/store/hello-world`, create the file `src/api/store/hello-world/route.ts` with the following content:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
|
|
13
|
-
|
|
14
|
-
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
15
|
-
res.json({
|
|
16
|
-
message: "Hello world!",
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Supported HTTP methods
|
|
22
|
-
|
|
23
|
-
The file based routing supports the following HTTP methods:
|
|
24
|
-
|
|
25
|
-
- GET
|
|
26
|
-
- POST
|
|
27
|
-
- PUT
|
|
28
|
-
- PATCH
|
|
29
|
-
- DELETE
|
|
30
|
-
- OPTIONS
|
|
31
|
-
- HEAD
|
|
32
|
-
|
|
33
|
-
You can define a handler for each of these methods by exporting a function with the name of the method in the paths `route.ts` file.
|
|
34
|
-
|
|
35
|
-
For example:
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
|
|
39
|
-
|
|
40
|
-
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
41
|
-
// Handle GET requests
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
45
|
-
// Handle POST requests
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function PUT(req: MedusaRequest, res: MedusaResponse) {
|
|
49
|
-
// Handle PUT requests
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Parameters
|
|
54
|
-
|
|
55
|
-
To create an API route that accepts a path parameter, create a directory within the route's path whose name is of the format `[param]`.
|
|
56
|
-
|
|
57
|
-
For example, if you want to define a route that takes a `productId` parameter, you can do so by creating a file called `/api/products/[productId]/route.ts`:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import type {
|
|
61
|
-
MedusaRequest,
|
|
62
|
-
MedusaResponse,
|
|
63
|
-
} from "@medusajs/framework/http"
|
|
64
|
-
|
|
65
|
-
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
66
|
-
const { productId } = req.params;
|
|
67
|
-
|
|
68
|
-
res.json({
|
|
69
|
-
message: `You're looking for product ${productId}`
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
To create an API route that accepts multiple path parameters, create within the file's path multiple directories whose names are of the format `[param]`.
|
|
75
|
-
|
|
76
|
-
For example, if you want to define a route that takes both a `productId` and a `variantId` parameter, you can do so by creating a file called `/api/products/[productId]/variants/[variantId]/route.ts`.
|
|
77
|
-
|
|
78
|
-
## Using the container
|
|
79
|
-
|
|
80
|
-
The Medusa container is available on `req.scope`. Use it to access modules' main services and other registered resources:
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import type {
|
|
84
|
-
MedusaRequest,
|
|
85
|
-
MedusaResponse,
|
|
86
|
-
} from "@medusajs/framework/http"
|
|
87
|
-
|
|
88
|
-
export const GET = async (
|
|
89
|
-
req: MedusaRequest,
|
|
90
|
-
res: MedusaResponse
|
|
91
|
-
) => {
|
|
92
|
-
const productModuleService = req.scope.resolve("product")
|
|
93
|
-
|
|
94
|
-
const [, count] = await productModuleService.listAndCount()
|
|
95
|
-
|
|
96
|
-
res.json({
|
|
97
|
-
count,
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Middleware
|
|
103
|
-
|
|
104
|
-
You can apply middleware to your routes by creating a file called `/api/middlewares.ts`. This file must export a configuration object with what middleware you want to apply to which routes.
|
|
105
|
-
|
|
106
|
-
For example, if you want to apply a custom middleware function to the `/store/custom` route, you can do so by adding the following to your `/api/middlewares.ts` file:
|
|
107
|
-
|
|
108
|
-
```ts
|
|
109
|
-
import { defineMiddlewares } from "@medusajs/framework/http"
|
|
110
|
-
import type {
|
|
111
|
-
MedusaRequest,
|
|
112
|
-
MedusaResponse,
|
|
113
|
-
MedusaNextFunction,
|
|
114
|
-
} from "@medusajs/framework/http";
|
|
115
|
-
|
|
116
|
-
async function logger(
|
|
117
|
-
req: MedusaRequest,
|
|
118
|
-
res: MedusaResponse,
|
|
119
|
-
next: MedusaNextFunction
|
|
120
|
-
) {
|
|
121
|
-
console.log("Request received");
|
|
122
|
-
next();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export default defineMiddlewares({
|
|
126
|
-
routes: [
|
|
127
|
-
{
|
|
128
|
-
matcher: "/store/custom",
|
|
129
|
-
middlewares: [logger],
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
})
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
The `matcher` property can be either a string or a regular expression. The `middlewares` property accepts an array of middleware functions.
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Custom scheduled jobs
|
|
2
|
-
|
|
3
|
-
A scheduled job is a function executed at a specified interval of time in the background of your Medusa application.
|
|
4
|
-
|
|
5
|
-
> Learn more about scheduled jobs in [this documentation](https://docs.medusajs.com/learn/fundamentals/scheduled-jobs).
|
|
6
|
-
|
|
7
|
-
A scheduled job is created in a TypeScript or JavaScript file under the `src/jobs` directory.
|
|
8
|
-
|
|
9
|
-
For example, create the file `src/jobs/hello-world.ts` with the following content:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import {
|
|
13
|
-
MedusaContainer
|
|
14
|
-
} from "@medusajs/framework/types";
|
|
15
|
-
|
|
16
|
-
export default async function myCustomJob(container: MedusaContainer) {
|
|
17
|
-
const productService = container.resolve("product")
|
|
18
|
-
|
|
19
|
-
const products = await productService.listAndCountProducts();
|
|
20
|
-
|
|
21
|
-
// Do something with the products
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const config = {
|
|
25
|
-
name: "daily-product-report",
|
|
26
|
-
schedule: "0 0 * * *", // Every day at midnight
|
|
27
|
-
};
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
A scheduled job file must export:
|
|
31
|
-
|
|
32
|
-
- The function to be executed whenever it’s time to run the scheduled job.
|
|
33
|
-
- A configuration object defining the job. It has three properties:
|
|
34
|
-
- `name`: a unique name for the job.
|
|
35
|
-
- `schedule`: a [cron expression](https://crontab.guru/).
|
|
36
|
-
- `numberOfExecutions`: an optional integer, specifying how many times the job will execute before being removed
|
|
37
|
-
|
|
38
|
-
The `handler` is a function that accepts one parameter, `container`, which is a `MedusaContainer` instance used to resolve services.
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Module Links
|
|
2
|
-
|
|
3
|
-
A module link forms an association between two data models of different modules, while maintaining module isolation.
|
|
4
|
-
|
|
5
|
-
> Learn more about links in [this documentation](https://docs.medusajs.com/learn/fundamentals/module-links)
|
|
6
|
-
|
|
7
|
-
For example:
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import BlogModule from "../modules/blog"
|
|
11
|
-
import ProductModule from "@medusajs/medusa/product"
|
|
12
|
-
import { defineLink } from "@medusajs/framework/utils"
|
|
13
|
-
|
|
14
|
-
export default defineLink(
|
|
15
|
-
ProductModule.linkable.product,
|
|
16
|
-
BlogModule.linkable.post
|
|
17
|
-
)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This defines a link between the Product Module's `product` data model and the Blog Module (custom module)'s `post` data model.
|
|
21
|
-
|
|
22
|
-
Then, in the Medusa application, run the following command to sync the links to the database:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npx medusa db:migrate
|
|
26
|
-
```
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# Custom Module
|
|
2
|
-
|
|
3
|
-
A module is a package of reusable functionalities. It can be integrated into your Medusa application without affecting the overall system. You can create a module as part of a plugin.
|
|
4
|
-
|
|
5
|
-
> Learn more about modules in [this documentation](https://docs.medusajs.com/learn/fundamentals/modules).
|
|
6
|
-
|
|
7
|
-
To create a module:
|
|
8
|
-
|
|
9
|
-
## 1. Create a Data Model
|
|
10
|
-
|
|
11
|
-
A data model represents a table in the database. You create a data model in a TypeScript or JavaScript file under the `models` directory of a module.
|
|
12
|
-
|
|
13
|
-
For example, create the file `src/modules/blog/models/post.ts` with the following content:
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { model } from "@medusajs/framework/utils"
|
|
17
|
-
|
|
18
|
-
const Post = model.define("post", {
|
|
19
|
-
id: model.id().primaryKey(),
|
|
20
|
-
title: model.text(),
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
export default Post
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## 2. Create a Service
|
|
27
|
-
|
|
28
|
-
A module must define a service. A service is a TypeScript or JavaScript class holding methods related to a business logic or commerce functionality.
|
|
29
|
-
|
|
30
|
-
For example, create the file `src/modules/blog/service.ts` with the following content:
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
import { MedusaService } from "@medusajs/framework/utils"
|
|
34
|
-
import Post from "./models/post"
|
|
35
|
-
|
|
36
|
-
class BlogModuleService extends MedusaService({
|
|
37
|
-
Post,
|
|
38
|
-
}){
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default BlogModuleService
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## 3. Export Module Definition
|
|
45
|
-
|
|
46
|
-
A module must have an `index.ts` file in its root directory that exports its definition. The definition specifies the main service of the module.
|
|
47
|
-
|
|
48
|
-
For example, create the file `src/modules/blog/index.ts` with the following content:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import BlogModuleService from "./service"
|
|
52
|
-
import { Module } from "@medusajs/framework/utils"
|
|
53
|
-
|
|
54
|
-
export const BLOG_MODULE = "blog"
|
|
55
|
-
|
|
56
|
-
export default Module(BLOG_MODULE, {
|
|
57
|
-
service: BlogModuleService,
|
|
58
|
-
})
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## 4. Add Module to Medusa's Configurations
|
|
62
|
-
|
|
63
|
-
To start using the module, add it to `medusa-config.ts`:
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
module.exports = defineConfig({
|
|
67
|
-
projectConfig: {
|
|
68
|
-
// ...
|
|
69
|
-
},
|
|
70
|
-
modules: [
|
|
71
|
-
{
|
|
72
|
-
resolve: "./src/modules/blog",
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
})
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## 5. Generate and Run Migrations
|
|
79
|
-
|
|
80
|
-
To generate migrations for your module, run the following command:
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
npx medusa db:generate blog
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Then, to run migrations, run the following command:
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
npx medusa db:migrate
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Use Module
|
|
93
|
-
|
|
94
|
-
You can use the module in customizations within the Medusa application, such as workflows and API routes.
|
|
95
|
-
|
|
96
|
-
For example, to use the module in an API route:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
import { MedusaRequest, MedusaResponse } from "@medusajs/framework"
|
|
100
|
-
import BlogModuleService from "../../../modules/blog/service"
|
|
101
|
-
import { BLOG_MODULE } from "../../../modules/blog"
|
|
102
|
-
|
|
103
|
-
export async function GET(
|
|
104
|
-
req: MedusaRequest,
|
|
105
|
-
res: MedusaResponse
|
|
106
|
-
): Promise<void> {
|
|
107
|
-
const blogModuleService: BlogModuleService = req.scope.resolve(
|
|
108
|
-
BLOG_MODULE
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
const posts = await blogModuleService.listPosts()
|
|
112
|
-
|
|
113
|
-
res.json({
|
|
114
|
-
posts
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
```
|