docs: various improvements to introduction guides (#14398)

This commit is contained in:
Shahed Nasser
2025-12-24 15:37:37 +02:00
committed by GitHub
parent 10dab3a47a
commit ba3a572a89
9 changed files with 61 additions and 53 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,

View File

@@ -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",

View File

@@ -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
)

View File

@@ -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:
![Example of subscriber file in the application's directory structure](https://res.cloudinary.com/dza7lstvk/image/upload/v1732866244/Medusa%20Book/subscriber-dir-overview_pusyeu.jpg)
```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"

View File

@@ -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,

View File

@@ -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",

View File

@@ -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-sessions 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-sessions 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-sessions 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-sessions 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-sessions 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-sessions 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:
![Example of subscriber file in the application's directory structure](https://res.cloudinary.com/dza7lstvk/image/upload/v1732866244/Medusa%20Book/subscriber-dir-overview_pusyeu.jpg)
```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.