From ba3a572a8969d35c4245265ce60596ecf81fac7c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 24 Dec 2025 15:37:37 +0200 Subject: [PATCH] docs: various improvements to introduction guides (#14398) --- .../integration-tests/api-routes/page.mdx | 4 +- .../testing-tools/integration-tests/page.mdx | 4 +- .../learn/fundamentals/admin/routing/page.mdx | 5 +- .../learn/fundamentals/admin/tips/page.mdx | 1 + .../fundamentals/custom-cli-scripts/page.mdx | 3 +- .../events-and-subscribers/page.mdx | 6 +- .../app/learn/fundamentals/modules/page.mdx | 11 ++-- www/apps/book/generated/edit-dates.mjs | 14 ++-- www/apps/book/public/llms-full.txt | 66 ++++++++++--------- 9 files changed, 61 insertions(+), 53 deletions(-) diff --git a/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx b/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx index 7546040723..cea8d3b987 100644 --- a/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx +++ b/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/api-routes/page.mdx @@ -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 ``` -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). diff --git a/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx b/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx index 5f14157a4b..47e134d2f5 100644 --- a/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx +++ b/www/apps/book/app/learn/debugging-and-testing/testing-tools/integration-tests/page.mdx @@ -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 ``` -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). diff --git a/www/apps/book/app/learn/fundamentals/admin/routing/page.mdx b/www/apps/book/app/learn/fundamentals/admin/routing/page.mdx index d154b4bd7e..deb6db05a6 100644 --- a/www/apps/book/app/learn/fundamentals/admin/routing/page.mdx +++ b/www/apps/book/app/learn/fundamentals/admin/routing/page.mdx @@ -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, diff --git a/www/apps/book/app/learn/fundamentals/admin/tips/page.mdx b/www/apps/book/app/learn/fundamentals/admin/tips/page.mdx index 1481e91c39..b50fefd216 100644 --- a/www/apps/book/app/learn/fundamentals/admin/tips/page.mdx +++ b/www/apps/book/app/learn/fundamentals/admin/tips/page.mdx @@ -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", diff --git a/www/apps/book/app/learn/fundamentals/custom-cli-scripts/page.mdx b/www/apps/book/app/learn/fundamentals/custom-cli-scripts/page.mdx index 0f1f5775d7..3d347b5949 100644 --- a/www/apps/book/app/learn/fundamentals/custom-cli-scripts/page.mdx +++ b/www/apps/book/app/learn/fundamentals/custom-cli-scripts/page.mdx @@ -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 ) diff --git a/www/apps/book/app/learn/fundamentals/events-and-subscribers/page.mdx b/www/apps/book/app/learn/fundamentals/events-and-subscribers/page.mdx index da973ea5c3..ca154081a6 100644 --- a/www/apps/book/app/learn/fundamentals/events-and-subscribers/page.mdx +++ b/www/apps/book/app/learn/fundamentals/events-and-subscribers/page.mdx @@ -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" diff --git a/www/apps/book/app/learn/fundamentals/modules/page.mdx b/www/apps/book/app/learn/fundamentals/modules/page.mdx index 5ae833c23e..5f6b5eb022 100644 --- a/www/apps/book/app/learn/fundamentals/modules/page.mdx +++ b/www/apps/book/app/learn/fundamentals/modules/page.mdx @@ -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, diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index 49a0c50c0a..fb48d8cfba 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -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", diff --git a/www/apps/book/public/llms-full.txt b/www/apps/book/public/llms-full.txt index 85e7a7709d..ec78996b55 100644 --- a/www/apps/book/public/llms-full.txt +++ b/www/apps/book/public/llms-full.txt @@ -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: -![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.