docs: various improvements to introduction guides (#14398)
This commit is contained in:
@@ -77,12 +77,12 @@ You add a single test that sends a `GET` request to `/custom` using the `api.get
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands).
|
||||
If you don't have a `test:integration:http` script in `package.json`, refer to the [Medusa Testing Tools chapter](../../page.mdx#add-test-commands).
|
||||
|
||||
</Note>
|
||||
|
||||
|
||||
@@ -68,12 +68,12 @@ jest.setTimeout(60 * 1000)
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](../page.mdx#add-test-commands).
|
||||
If you don't have a `test:integration:http` script in `package.json`, refer to the [Medusa Testing Tools chapter](../page.mdx#add-test-commands).
|
||||
|
||||
</Note>
|
||||
|
||||
|
||||
@@ -71,11 +71,12 @@ To fetch data with a route loader:
|
||||
For example, consider the following UI route created at `src/admin/routes/custom/page.tsx`:
|
||||
|
||||
export const loaderHighlights = [
|
||||
["6", "loader", "Export a loader function to fetch products."],
|
||||
["15", "useLoaderData", "Access the data returned by the loader function in the route component."],
|
||||
["7", "loader", "Export a loader function to fetch products."],
|
||||
["16", "useLoaderData", "Access the data returned by the loader function in the route component."],
|
||||
]
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={loaderHighlights}
|
||||
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
import {
|
||||
useLoaderData,
|
||||
|
||||
@@ -42,6 +42,7 @@ export const sdk = new Medusa({
|
||||
import Medusa from "@medusajs/js-sdk"
|
||||
|
||||
export const sdk = new Medusa({
|
||||
// add __BACKEND_URL__ to src/admin/vite-env.d.ts if you get type errors
|
||||
baseUrl: __BACKEND_URL__ || "/",
|
||||
auth: {
|
||||
type: "session",
|
||||
|
||||
@@ -26,12 +26,11 @@ For example, create the file `src/scripts/my-script.ts` with the following conte
|
||||
```ts title="src/scripts/my-script.ts"
|
||||
import {
|
||||
ExecArgs,
|
||||
IProductModuleService,
|
||||
} from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
export default async function myScript({ container }: ExecArgs) {
|
||||
const productModuleService: IProductModuleService = container.resolve(
|
||||
const productModuleService = container.resolve(
|
||||
Modules.PRODUCT
|
||||
)
|
||||
|
||||
|
||||
@@ -34,11 +34,9 @@ Find a list of all emitted events in [this reference](!resources!/references/eve
|
||||
|
||||
You create a subscriber in a TypeScript or JavaScript file under the `src/subscribers` directory. The file exports the function to execute and the subscriber's configuration that indicate what event(s) it listens to.
|
||||
|
||||
For example, create the file `src/subscribers/product-created.ts` with the following content:
|
||||
For example, create the file `src/subscribers/order-placed.ts` with the following content:
|
||||
|
||||

|
||||
|
||||
```ts title="src/subscribers/product-created.ts"
|
||||
```ts title="src/subscribers/order-placed.ts"
|
||||
import { SubscriberArgs, type SubscriberConfig } from "@medusajs/framework"
|
||||
import { sendOrderConfirmationWorkflow } from "../workflows/send-order-confirmation"
|
||||
|
||||
|
||||
@@ -256,9 +256,9 @@ export const workflowHighlights = [
|
||||
["17", "resolve", "Resolve the Blog Module's service from the Medusa container."],
|
||||
["19", "createPosts", "Create a blog post using the Blog Module service's generated method."],
|
||||
["25", "", "Add a compensation function that only runs if an error occurs in the workflow."],
|
||||
["28", "", "Delete the post if an error occurs using the Blog Module service's generated method."],
|
||||
["32", "createWorkflow", "Create and workflow that can be executed to create a blog post."],
|
||||
["35", "createPostStep", "Execute the `createPostStep` to create the post."]
|
||||
["31", "deletePosts", "Delete the post if an error occurs using the Blog Module service's generated method."],
|
||||
["35", "createWorkflow", "Create and workflow that can be executed to create a blog post."],
|
||||
["38", "createPostStep", "Execute the `createPostStep` to create the post."]
|
||||
]
|
||||
|
||||
```ts title="src/workflows/create-post.ts" highlights={workflowHighlights}
|
||||
@@ -287,6 +287,9 @@ const createPostStep = createStep(
|
||||
return new StepResponse(post, post)
|
||||
},
|
||||
async (post, { container }) => {
|
||||
if (!post) {
|
||||
return
|
||||
}
|
||||
const blogModuleService: BlogModuleService = container.resolve(BLOG_MODULE)
|
||||
|
||||
await blogModuleService.deletePosts(post.id)
|
||||
@@ -309,7 +312,7 @@ The step also has a compensation function, which is a function passed as a third
|
||||
|
||||
You'll now execute that workflow in an API route to expose the feature of creating blog posts to clients. To create an API route, create the file `src/api/blog/posts/route.ts` with the following content:
|
||||
|
||||
```ts
|
||||
```ts title="src/api/blog/posts/route.ts"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
|
||||
@@ -15,7 +15,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/medusa-container/page.mdx": "2025-07-25T13:18:36.859Z",
|
||||
"app/learn/fundamentals/api-routes/page.mdx": "2025-07-25T15:19:33.365Z",
|
||||
"app/learn/fundamentals/modules/modules-directory-structure/page.mdx": "2025-07-25T15:40:20.362Z",
|
||||
"app/learn/fundamentals/events-and-subscribers/page.mdx": "2025-10-16T09:36:04.864Z",
|
||||
"app/learn/fundamentals/events-and-subscribers/page.mdx": "2025-12-23T07:31:36.184Z",
|
||||
"app/learn/fundamentals/modules/container/page.mdx": "2025-07-31T14:24:04.087Z",
|
||||
"app/learn/fundamentals/workflows/execute-another-workflow/page.mdx": "2025-08-01T07:28:51.036Z",
|
||||
"app/learn/fundamentals/modules/loaders/page.mdx": "2025-10-09T11:41:31.724Z",
|
||||
@@ -43,15 +43,15 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/scheduled-jobs/execution-number/page.mdx": "2025-07-25T15:54:56.135Z",
|
||||
"app/learn/fundamentals/api-routes/parameters/page.mdx": "2025-09-15T15:47:08.409Z",
|
||||
"app/learn/fundamentals/api-routes/http-methods/page.mdx": "2025-07-25T15:12:29.347Z",
|
||||
"app/learn/fundamentals/admin/tips/page.mdx": "2025-10-03T08:35:15.022Z",
|
||||
"app/learn/fundamentals/admin/tips/page.mdx": "2025-12-23T08:24:29.078Z",
|
||||
"app/learn/fundamentals/api-routes/cors/page.mdx": "2025-03-11T08:54:26.281Z",
|
||||
"app/learn/fundamentals/admin/ui-routes/page.mdx": "2025-07-25T06:58:26.149Z",
|
||||
"app/learn/fundamentals/api-routes/middlewares/page.mdx": "2025-10-16T11:23:37.787Z",
|
||||
"app/learn/fundamentals/modules/isolation/page.mdx": "2025-05-21T15:10:15.499Z",
|
||||
"app/learn/fundamentals/data-models/index/page.mdx": "2025-03-18T07:59:07.798Z",
|
||||
"app/learn/fundamentals/custom-cli-scripts/page.mdx": "2025-07-25T15:32:47.587Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-09-02T08:36:12.714Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2024-12-09T15:52:01.019Z",
|
||||
"app/learn/fundamentals/custom-cli-scripts/page.mdx": "2025-12-23T07:33:58.063Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx": "2025-12-23T07:53:58.179Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx": "2025-12-23T07:54:27.757Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/integration-tests/workflows/page.mdx": "2025-07-30T13:43:44.636Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/page.mdx": "2025-10-28T16:01:29.630Z",
|
||||
"app/learn/debugging-and-testing/testing-tools/unit-tests/module-example/page.mdx": "2024-09-02T11:04:27.232Z",
|
||||
@@ -68,7 +68,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/module-links/query/page.mdx": "2025-10-27T09:30:26.957Z",
|
||||
"app/learn/fundamentals/modules/db-operations/page.mdx": "2025-10-28T16:02:06.265Z",
|
||||
"app/learn/fundamentals/modules/multiple-services/page.mdx": "2025-03-18T15:11:44.632Z",
|
||||
"app/learn/fundamentals/modules/page.mdx": "2025-10-28T16:02:08.857Z",
|
||||
"app/learn/fundamentals/modules/page.mdx": "2025-12-23T07:00:14.586Z",
|
||||
"app/learn/debugging-and-testing/instrumentation/page.mdx": "2025-10-09T11:37:32.815Z",
|
||||
"app/learn/fundamentals/api-routes/additional-data/page.mdx": "2025-04-17T08:50:17.036Z",
|
||||
"app/learn/fundamentals/workflows/variable-manipulation/page.mdx": "2025-04-24T13:14:43.967Z",
|
||||
@@ -107,7 +107,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/module-links/query-context/page.mdx": "2025-09-15T16:09:58.104Z",
|
||||
"app/learn/fundamentals/admin/environment-variables/page.mdx": "2025-11-26T08:24:17.689Z",
|
||||
"app/learn/fundamentals/api-routes/parse-body/page.mdx": "2025-08-20T09:58:37.704Z",
|
||||
"app/learn/fundamentals/admin/routing/page.mdx": "2025-07-25T07:35:18.038Z",
|
||||
"app/learn/fundamentals/admin/routing/page.mdx": "2025-12-23T07:45:07.801Z",
|
||||
"app/learn/resources/contribution-guidelines/admin-translations/page.mdx": "2025-02-11T16:57:46.726Z",
|
||||
"app/learn/resources/contribution-guidelines/docs/page.mdx": "2025-09-26T13:53:55.070Z",
|
||||
"app/learn/resources/usage/page.mdx": "2025-02-26T13:35:34.824Z",
|
||||
|
||||
@@ -1826,8 +1826,8 @@ module.exports = defineConfig({
|
||||
|
||||
Aside from the following options, you can pass any property that the [express-session's cookie option accepts](https://www.npmjs.com/package/express-session).
|
||||
|
||||
- secure: (\`boolean\`)
|
||||
- sameSite: (\`lax\` | \`strict\` | \`none\`)
|
||||
- secure: (\`boolean\`) Whether the cookie should only be sent over HTTPS. This is useful in production environments where you want to ensure that cookies are only sent over secure connections.
|
||||
- sameSite: (\`lax\` | \`strict\` | \`none\`) Controls the SameSite attribute of the cookie.
|
||||
- maxAge: (\`number\`) The maximum age of the cookie in milliseconds set in the \`Set-Cookie\` header.
|
||||
- httpOnly: (\`boolean\`) Whether to set the \`HttpOnly Set-Cookie\` attribute.
|
||||
- priority: (\`low\` | \`medium\` | \`high\`) The value of the \[Priority Set-Cookie attribute]\(https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1)
|
||||
@@ -1858,22 +1858,24 @@ When you disable `rejectUnauthorized`, make sure to also add `?ssl_mode=disable`
|
||||
|
||||
#### Properties
|
||||
|
||||
- connection: (\`object\`)
|
||||
- connection: (\`object\`) An object of connection options.
|
||||
|
||||
- ssl: (\`object\` | \`boolean\`)
|
||||
- ssl: (\`object\` | \`boolean\`) Either a boolean indicating whether to use SSL or an object of SSL options. You can find the full list of options in the \[Node.js documentation]\(https://nodejs.org/docs/latest-v20.x/api/tls.html#tlsconnectoptions-callback).
|
||||
|
||||
- pool: (\`object\`)
|
||||
- rejectUnauthorized: (boolean) Whether to reject unauthorized connections.
|
||||
|
||||
- min: (\`number\`)
|
||||
- pool: (\`object\`) An object of options initialized by the underlying \[knex]\(https://knexjs.org/guide/#pool) client.
|
||||
|
||||
- max: (\`number\`)
|
||||
- min: (\`number\`) The minimum number of connections in the pool.
|
||||
|
||||
- idleTimeoutMillis: (\`number\`)
|
||||
- max: (\`number\`) The maximum number of connections in the pool.
|
||||
|
||||
- reapIntervalMillis: (\`number\`)
|
||||
- idleTimeoutMillis: (\`number\`) The maximum time, in milliseconds, that a connection can be idle before being released.
|
||||
|
||||
- createRetryIntervalMillis: (\`number\`)
|
||||
- idle\_in\_transaction\_session\_timeout: (\`number\`)
|
||||
- reapIntervalMillis: (\`number\`) How often to check for idle connections that can be released.
|
||||
|
||||
- createRetryIntervalMillis: (\`number\`) How long to wait before retrying to create a connection after a failure.
|
||||
- idle\_in\_transaction\_session\_timeout: (\`number\`) The maximum time, in milliseconds, that a session can be idle before being terminated.
|
||||
|
||||
### databaseLogging
|
||||
|
||||
@@ -2273,7 +2275,7 @@ module.exports = defineConfig({
|
||||
|
||||
This configuation is an object that accepts the following properties:
|
||||
|
||||
- enabled: (\`boolean\`)
|
||||
- enabled: (\`boolean\`) Whether to enable HTTP compression.
|
||||
- level: (\`number\`) The level of zlib compression to apply to responses. A higher level will result in better compression but will take longer to complete. A lower level will result in less compression but will be much faster.
|
||||
- memLevel: (\`number\`) How much memory should be allocated to the internal compression state. It value is between \`1\` (minimum level) and \`9\` (maximum level).
|
||||
- threshold: (\`number\` | \`string\`) The minimum response body size that compression is applied on. Its value can be the number of bytes or any string accepted by the \[bytes]\(https://www.npmjs.com/package/bytes) package.
|
||||
@@ -2329,7 +2331,7 @@ module.exports = defineConfig({
|
||||
|
||||
The `restrictedFields` configuration accepts the following properties:
|
||||
|
||||
- store: (\`string\[]\`)
|
||||
- store: (\`string\[]\`) An array of fields that can't be selected in store API routes.
|
||||
|
||||
### redisOptions
|
||||
|
||||
@@ -2430,10 +2432,10 @@ module.exports = defineConfig({
|
||||
|
||||
#### Properties
|
||||
|
||||
- name: (\`string\`)
|
||||
- resave: (\`boolean\`)
|
||||
- rolling: (\`boolean\`)
|
||||
- saveUninitialized: (\`boolean\`)
|
||||
- name: (\`string\`) The name of the session ID cookie to set in the response (and read from in the request). Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#name) for more details.
|
||||
- resave: (\`boolean\`) Whether the session should be saved back to the session store, even if the session was never modified during the request. Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#resave) for more details.
|
||||
- rolling: (\`boolean\`) Whether the session identifier cookie should be force-set on every response. Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#rolling) for more details.
|
||||
- saveUninitialized: (\`boolean\`) Whether to save sessions that are new but not modified. Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#saveUninitialized) for more details.
|
||||
- secret: (\`string\`) The secret to sign the session ID cookie. By default, the value of \[http.cookieSecret]\(#httpcookieSecret) is used. Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#secret) for details.
|
||||
- ttl: (\`number\`) The time-to-live (TTL) of the session ID cookie in milliseconds. It is used when calculating the \`Expires\` \`Set-Cookie\` attribute of cookies. Refer to \[express-session’s documentation]\(https://www.npmjs.com/package/express-session#cookie) for more details.
|
||||
|
||||
@@ -6353,10 +6355,10 @@ You add a single test that sends a `GET` request to `/custom` using the `api.get
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools#add-test-commands/index.html.md).
|
||||
If you don't have a `test:integration:http` script in `package.json`, refer to the [Medusa Testing Tools chapter](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools#add-test-commands/index.html.md).
|
||||
|
||||
This runs your Medusa application and runs the tests available under the `src/integrations/http` directory.
|
||||
|
||||
@@ -6935,10 +6937,10 @@ jest.setTimeout(60 * 1000)
|
||||
Run the following command to run your tests:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run test:integration
|
||||
npm run test:integration:http
|
||||
```
|
||||
|
||||
If you don't have a `test:integration` script in `package.json`, refer to the [Medusa Testing Tools chapter](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools#add-test-commands/index.html.md).
|
||||
If you don't have a `test:integration:http` script in `package.json`, refer to the [Medusa Testing Tools chapter](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools#add-test-commands/index.html.md).
|
||||
|
||||
This runs your Medusa application and runs the tests available under the `src/integrations/http` directory.
|
||||
|
||||
@@ -8524,6 +8526,7 @@ To fetch data with a route loader:
|
||||
For example, consider the following UI route created at `src/admin/routes/custom/page.tsx`:
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={loaderHighlights}
|
||||
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
import {
|
||||
useLoaderData,
|
||||
@@ -8664,6 +8667,7 @@ export const sdk = new Medusa({
|
||||
import Medusa from "@medusajs/js-sdk"
|
||||
|
||||
export const sdk = new Medusa({
|
||||
// add __BACKEND_URL__ to src/admin/vite-env.d.ts if you get type errors
|
||||
baseUrl: __BACKEND_URL__ || "/",
|
||||
auth: {
|
||||
type: "session",
|
||||
@@ -11999,12 +12003,11 @@ For example, create the file `src/scripts/my-script.ts` with the following conte
|
||||
```ts title="src/scripts/my-script.ts"
|
||||
import {
|
||||
ExecArgs,
|
||||
IProductModuleService,
|
||||
} from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
export default async function myScript({ container }: ExecArgs) {
|
||||
const productModuleService: IProductModuleService = container.resolve(
|
||||
const productModuleService = container.resolve(
|
||||
Modules.PRODUCT
|
||||
)
|
||||
|
||||
@@ -14344,11 +14347,9 @@ Find a list of all emitted events in [this reference](https://docs.medusajs.com/
|
||||
|
||||
You create a subscriber in a TypeScript or JavaScript file under the `src/subscribers` directory. The file exports the function to execute and the subscriber's configuration that indicate what event(s) it listens to.
|
||||
|
||||
For example, create the file `src/subscribers/product-created.ts` with the following content:
|
||||
For example, create the file `src/subscribers/order-placed.ts` with the following content:
|
||||
|
||||

|
||||
|
||||
```ts title="src/subscribers/product-created.ts"
|
||||
```ts title="src/subscribers/order-placed.ts"
|
||||
import { SubscriberArgs, type SubscriberConfig } from "@medusajs/framework"
|
||||
import { sendOrderConfirmationWorkflow } from "../workflows/send-order-confirmation"
|
||||
|
||||
@@ -21194,6 +21195,9 @@ const createPostStep = createStep(
|
||||
return new StepResponse(post, post)
|
||||
},
|
||||
async (post, { container }) => {
|
||||
if (!post) {
|
||||
return
|
||||
}
|
||||
const blogModuleService: BlogModuleService = container.resolve(BLOG_MODULE)
|
||||
|
||||
await blogModuleService.deletePosts(post.id)
|
||||
@@ -21216,7 +21220,7 @@ The step also has a compensation function, which is a function passed as a third
|
||||
|
||||
You'll now execute that workflow in an API route to expose the feature of creating blog posts to clients. To create an API route, create the file `src/api/blog/posts/route.ts` with the following content:
|
||||
|
||||
```ts
|
||||
```ts title="src/api/blog/posts/route.ts"
|
||||
import type {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
@@ -122649,7 +122653,7 @@ The component accepts the following props:
|
||||
|
||||
- actions: (\`object\[]\`) Actions in the group.
|
||||
|
||||
- icon: (\`React.ReactNode\`)
|
||||
- icon: (\`React.ReactNode\`) The icon of the action. You can use icons from the \[Medusa Icons package]\(https://docs.medusajs.com/ui/icons/overview).
|
||||
|
||||
- label: (\`string\`) The action's text.
|
||||
|
||||
@@ -123974,7 +123978,9 @@ It accepts the following props:
|
||||
|
||||
\- If its value is \`custom\`, you can pass any React nodes to render.
|
||||
|
||||
- props: (object)
|
||||
- props: (object) This property is only accepted if \`type\` is \`button\` or \`action-menu\`. If \`type\` is \`button\`, it accepts the \[props to pass to the UI Button component]\(https://docs.medusajs.com/components/button). If \`type\` is \`action-menu\`, it accepts the props to pass to the action menu, explained in \[this guide]\(../action-menu/page.mdx).
|
||||
|
||||
- link: (\[LinkProps]\(https://reactrouter.com/en/main/components/link)) This property is only accepted if \`type\` is \`button\`. If provided, a link is rendered inside the button. Its value is the props to pass the \`Link\` component of \`react-router-dom\`.
|
||||
|
||||
- children: (React.ReactNode) This property is only accepted if \`type\` is \`custom\`. Its content is rendered as part of the actions.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user