docs: add keywords to cloud, fixes to installation and Index Module docs (#14129)

* docs: add keywords to cloud, fixes to installation and Index Module docs

* fix vale error
This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-11-26 14:36:29 +02:00
1 parent 458dc9d22b
commit 76660fb6cc
6 files changed
+69 -56

No files matched your search

@@ -28,7 +28,7 @@ The Index Module solves this problem by ingesting data into a central data store
### Ingested Data Models ### Ingested Data Models
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Data models are ingested if they're linked to other data models with the `filterable` property set, as you'll learn in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Medusa also ingests some core data models by default, such as `Product`, `ProductVariant`, `Price`, and `SalesChannel`.
<Note> <Note>
@@ -68,7 +68,7 @@ npx medusa db:migrate
### Ingest Data ### Ingest Data
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application: The Index Module only ingests data when you start your Medusa server. So, to [ingest data models](#ingested-data-models), start the Medusa application:
```bash npm2yarn ```bash npm2yarn
npm run dev npm run dev
@@ -177,7 +177,7 @@ The `index` method accepts an object with the same properties as the `graph` met
## How to Ingest Custom Data Models ## How to Ingest Custom Data Models
Aside from the [core data models](#ingested-data-models), you can also ingest your own custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition. You can ingest core and custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
<Note> <Note>
@@ -185,7 +185,7 @@ Read-only links are not supported by the Index Module.
</Note> </Note>
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](../../../customization/custom-features/module/page.mdx)), you can ingest it into the Index Module using the `filterable` property in its link definition to the Product data model: For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](../../../customization/custom-features/module/page.mdx)), you can ingest it into the Index Module using the `filterable` property in its link definition to the `Product` data model:
export const filterableHighlights = [ export const filterableHighlights = [
["12", "filterable", "Ingest Brand by setting its filterable properties."] ["12", "filterable", "Ingest Brand by setting its filterable properties."]
@@ -10,15 +10,15 @@ In this chapter, you'll learn how to install and run a Medusa application.
## Get Started with Cloud ## Get Started with Cloud
Cloud is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow. [Cloud](!cloud!) is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
Refer to the [Sign Up](!cloud!/sign-up) guide to create your first Medusa project in minutes. [Sign up](http://cloud.medusajs.com/signup) with Cloud and create your first Medusa project in minutes.
--- ---
## Create Medusa Application Locally ## Create Medusa Application Locally
A Medusa application is made up of a Node.js server and an admin dashboard. You can optionally install the [Next.js Starter Storefront](!resources!/nextjs-starter) separately either while installing the Medusa application or at a later point. A Medusa application is made up of a Node.js server and a Vite admin dashboard. You can optionally install the [Next.js Starter Storefront](!resources!/nextjs-starter) separately either while installing the Medusa application or at a later point.
<Note> <Note>
+2 -2
View File
@@ -96,7 +96,7 @@ export const generatedEditDates = {
"app/learn/build/page.mdx": "2025-10-27T09:30:26.957Z", "app/learn/build/page.mdx": "2025-10-27T09:30:26.957Z",
"app/learn/deployment/general/page.mdx": "2025-10-21T07:39:08.998Z", "app/learn/deployment/general/page.mdx": "2025-10-21T07:39:08.998Z",
"app/learn/fundamentals/workflows/multiple-step-usage/page.mdx": "2025-08-01T14:59:59.501Z", "app/learn/fundamentals/workflows/multiple-step-usage/page.mdx": "2025-08-01T14:59:59.501Z",
"app/learn/installation/page.mdx": "2025-10-24T09:22:44.583Z", "app/learn/installation/page.mdx": "2025-11-26T12:14:47.372Z",
"app/learn/fundamentals/data-models/check-constraints/page.mdx": "2025-07-25T13:50:21.065Z", "app/learn/fundamentals/data-models/check-constraints/page.mdx": "2025-07-25T13:50:21.065Z",
"app/learn/fundamentals/module-links/link/page.mdx": "2025-04-07T08:03:14.513Z", "app/learn/fundamentals/module-links/link/page.mdx": "2025-04-07T08:03:14.513Z",
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-04-17T08:29:10.166Z", "app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-04-17T08:29:10.166Z",
@@ -121,7 +121,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z", "app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z",
"app/learn/fundamentals/api-routes/override/page.mdx": "2025-05-09T08:01:24.493Z", "app/learn/fundamentals/api-routes/override/page.mdx": "2025-05-09T08:01:24.493Z",
"app/learn/fundamentals/module-links/index/page.mdx": "2025-05-23T07:57:58.958Z", "app/learn/fundamentals/module-links/index/page.mdx": "2025-05-23T07:57:58.958Z",
"app/learn/fundamentals/module-links/index-module/page.mdx": "2025-10-30T11:31:29.704Z", "app/learn/fundamentals/module-links/index-module/page.mdx": "2025-11-26T11:20:25.961Z",
"app/learn/introduction/build-with-llms-ai/page.mdx": "2025-10-02T15:10:49.394Z", "app/learn/introduction/build-with-llms-ai/page.mdx": "2025-10-02T15:10:49.394Z",
"app/learn/installation/docker/page.mdx": "2025-10-24T08:53:46.445Z", "app/learn/installation/docker/page.mdx": "2025-10-24T08:53:46.445Z",
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z", "app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
+46 -46
View File
@@ -14684,7 +14684,7 @@ The Index Module solves this problem by ingesting data into a central data store
### Ingested Data Models ### Ingested Data Models
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Data models are ingested if they're linked to other data models with the `filterable` property set, as you'll learn in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Medusa also ingests some core data models by default, such as `Product`, `ProductVariant`, `Price`, and `SalesChannel`.
Prior to [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2), only the `Product`, `ProductVariant`, `Price`, and `SalesChannel` data models were ingested. Make sure to update to the latest version to ingest all core data models. Prior to [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2), only the `Product`, `ProductVariant`, `Price`, and `SalesChannel` data models were ingested. Make sure to update to the latest version to ingest all core data models.
@@ -14720,7 +14720,7 @@ npx medusa db:migrate
### Ingest Data ### Ingest Data
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application: The Index Module only ingests data when you start your Medusa server. So, to [ingest data models](#ingested-data-models), start the Medusa application:
```bash npm2yarn ```bash npm2yarn
npm run dev npm run dev
@@ -14825,11 +14825,11 @@ The `index` method accepts an object with the same properties as the `graph` met
## How to Ingest Custom Data Models ## How to Ingest Custom Data Models
Aside from the [core data models](#ingested-data-models), you can also ingest your own custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition. You can ingest core and custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
Read-only links are not supported by the Index Module. Read-only links are not supported by the Index Module.
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](https://docs.medusajs.com/learn/customization/custom-features/module/index.html.md)), you can ingest it into the Index Module using the `filterable` property in its link definition to the Product data model: For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](https://docs.medusajs.com/learn/customization/custom-features/module/index.html.md)), you can ingest it into the Index Module using the `filterable` property in its link definition to the `Product` data model:
```ts title="src/links/product-brand.ts" highlights={filterableHighlights} ```ts title="src/links/product-brand.ts" highlights={filterableHighlights}
import BrandModule from "../modules/brand" import BrandModule from "../modules/brand"
@@ -24296,15 +24296,15 @@ In this chapter, you'll learn how to install and run a Medusa application.
## Get Started with Cloud ## Get Started with Cloud
Cloud is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow. [Cloud](https://docs.medusajs.com/cloud/index.html.md) is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
Refer to the [Sign Up](https://docs.medusajs.com/cloud/sign-up/index.html.md) guide to create your first Medusa project in minutes. [Sign up](http://cloud.medusajs.com/signup) with Cloud and create your first Medusa project in minutes.
*** ***
## Create Medusa Application Locally ## Create Medusa Application Locally
A Medusa application is made up of a Node.js server and an admin dashboard. You can optionally install the [Next.js Starter Storefront](https://docs.medusajs.com/resources/nextjs-starter/index.html.md) separately either while installing the Medusa application or at a later point. A Medusa application is made up of a Node.js server and a Vite admin dashboard. You can optionally install the [Next.js Starter Storefront](https://docs.medusajs.com/resources/nextjs-starter/index.html.md) separately either while installing the Medusa application or at a later point.
While this is the recommended way to create a Medusa application, you can alternatively [install a Medusa application with Docker](https://docs.medusajs.com/learn/installation/docker/index.html.md). While this is the recommended way to create a Medusa application, you can alternatively [install a Medusa application with Docker](https://docs.medusajs.com/learn/installation/docker/index.html.md).
@@ -65737,7 +65737,7 @@ export const TierRule = model.define("tier_rule", {
{ {
on: ["tier_id", "currency_code"], on: ["tier_id", "currency_code"],
unique: true, unique: true,
} },
]) ])
``` ```
@@ -65876,7 +65876,7 @@ import CustomerModule from "@medusajs/medusa/customer"
export default defineLink( export default defineLink(
{ {
linkable: TierModule.linkable.tier, linkable: TierModule.linkable.tier,
filterable: ["id"] filterable: ["id"],
}, },
{ {
linkable: CustomerModule.linkable.customer, linkable: CustomerModule.linkable.customer,
@@ -66018,7 +66018,7 @@ export const createTierRulesStep = createStep(
const tierModuleService = container.resolve(TIER_MODULE) const tierModuleService = container.resolve(TIER_MODULE)
const createdRules = await tierModuleService.createTierRules( const createdRules = await tierModuleService.createTierRules(
input.tier_rules.map(rule => ({ input.tier_rules.map((rule) => ({
tier_id: input.tier_id, tier_id: input.tier_id,
min_purchase_value: rule.min_purchase_value, min_purchase_value: rule.min_purchase_value,
currency_code: rule.currency_code, currency_code: rule.currency_code,
@@ -66033,7 +66033,7 @@ export const createTierRulesStep = createStep(
} }
const tierModuleService = container.resolve(TIER_MODULE) const tierModuleService = container.resolve(TIER_MODULE)
await tierModuleService.deleteTierRules(createdRules.map(rule => rule.id)) await tierModuleService.deleteTierRules(createdRules.map((rule) => rule.id))
} }
) )
``` ```
@@ -66082,7 +66082,7 @@ export const createTierWorkflow = createWorkflow(
}, },
options: { options: {
throwIfKeyNotFound: true, throwIfKeyNotFound: true,
} },
}) })
}) })
// Create the tier // Create the tier
@@ -67005,7 +67005,7 @@ export const deleteTierRulesStep = createStep(
const tierModuleService: TierModuleService = container.resolve(TIER_MODULE) const tierModuleService: TierModuleService = container.resolve(TIER_MODULE)
// Restore deleted rules // Restore deleted rules
await tierModuleService.createTierRules( await tierModuleService.createTierRules(
compensationData.map(rule => ({ compensationData.map((rule) => ({
tier_id: rule.tier_id, tier_id: rule.tier_id,
min_purchase_value: rule.min_purchase_value, min_purchase_value: rule.min_purchase_value,
currency_code: rule.currency_code, currency_code: rule.currency_code,
@@ -67060,7 +67060,7 @@ export const updateTierWorkflow = createWorkflow(
}, },
options: { options: {
throwIfKeyNotFound: true, throwIfKeyNotFound: true,
} },
}) })
// Validate promotion if provided // Validate promotion if provided
when({ input }, (data) => !!data.input.promo_id) when({ input }, (data) => !!data.input.promo_id)
@@ -67073,7 +67073,7 @@ export const updateTierWorkflow = createWorkflow(
}, },
options: { options: {
throwIfKeyNotFound: true, throwIfKeyNotFound: true,
} },
}).config({ name: "retrieve-promotion" }) }).config({ name: "retrieve-promotion" })
}) })
// Update the tier // Update the tier
@@ -67089,10 +67089,10 @@ export const updateTierWorkflow = createWorkflow(
const ids = transform({ const ids = transform({
tiers, tiers,
}, (data) => { }, (data) => {
return (data.tiers[0].tier_rules?.map(rule => rule?.id) || []) as string[] return (data.tiers[0].tier_rules?.map((rule) => rule?.id) || []) as string[]
}) })
deleteTierRulesStep({ deleteTierRulesStep({
ids ids,
}) })
return createTierRulesStep({ return createTierRulesStep({
tier_id: input.id, tier_id: input.id,
@@ -67205,8 +67205,8 @@ export default defineMiddlewares({
matcher: "/admin/tiers/:id", matcher: "/admin/tiers/:id",
methods: ["POST"], methods: ["POST"],
middlewares: [validateAndTransformBody(UpdateTierSchema)], middlewares: [validateAndTransformBody(UpdateTierSchema)],
} },
] ],
}) })
``` ```
@@ -67288,7 +67288,7 @@ export default defineMiddlewares({
}), }),
], ],
}, },
] ],
}) })
``` ```
@@ -67319,8 +67319,8 @@ export default config({
// ... // ...
{ {
resolve: "@medusajs/index", resolve: "@medusajs/index",
} },
] ],
}) })
``` ```
@@ -67426,7 +67426,7 @@ const { data: storeData } = useQuery({
const updateTierMutation = useMutation({ const updateTierMutation = useMutation({
mutationFn: async (data: EditTierFormData) => { mutationFn: async (data: EditTierFormData) => {
if (!tier) return if (!tier) {return}
return await sdk.client.fetch(`/admin/tiers/${tier.id}`, { return await sdk.client.fetch(`/admin/tiers/${tier.id}`, {
method: "POST", method: "POST",
body: data, body: data,
@@ -67984,7 +67984,7 @@ In `src/admin/routes/tiers/page.tsx`, find the `onRowClick` handler and replace
```tsx title="src/admin/routes/tiers/page.tsx" ```tsx title="src/admin/routes/tiers/page.tsx"
onRowClick: (_event, row) => { onRowClick: (_event, row) => {
navigate(`/tiers/${row.id}`) navigate(`/tiers/${row.id}`)
}, }
``` ```
You navigate to the tier details page when the user clicks on a tier in the tiers list. You navigate to the tier details page when the user clicks on a tier in the tiers list.
@@ -68042,12 +68042,12 @@ class TierModuleService extends MedusaService({
}) { }) {
async calculateQualifyingTier( async calculateQualifyingTier(
currencyCode: string, currencyCode: string,
purchaseValue: number, purchaseValue: number
) { ) {
const rules = await this.listTierRules( const rules = await this.listTierRules(
{ {
currency_code: currencyCode, currency_code: currencyCode,
}, }
) )
if (!rules || rules.length === 0) { if (!rules || rules.length === 0) {
@@ -68205,7 +68205,7 @@ export const updateCustomerTierOnOrderWorkflow = createWorkflow(
}, },
options: { options: {
throwIfKeyNotFound: true, throwIfKeyNotFound: true,
} },
}) })
const validatedCustomer = validateCustomerStep({ const validatedCustomer = validateCustomerStep({
@@ -68223,8 +68223,8 @@ export const updateCustomerTierOnOrderWorkflow = createWorkflow(
$nin: [ $nin: [
OrderStatus.CANCELED, OrderStatus.CANCELED,
OrderStatus.DRAFT, OrderStatus.DRAFT,
] ],
} },
}, },
}).config({ name: "completed-orders" }) }).config({ name: "completed-orders" })
@@ -68638,8 +68638,8 @@ updateCartPromotionsWorkflow.hooks.validate(async ({ input, cart }, { container
entity: "tier", entity: "tier",
fields: ["id", "promo_id"], fields: ["id", "promo_id"],
filters: { filters: {
promo_id: promotions.map((p) => p.id) promo_id: promotions.map((p) => p.id),
} },
}) })
// Validate each promotion being added // Validate each promotion being added
@@ -68714,8 +68714,8 @@ completeCartWorkflow.hooks.validate(async ({ cart }, { container }) => {
entity: "tier", entity: "tier",
fields: ["id", "promo_id"], fields: ["id", "promo_id"],
filters: { filters: {
promo_id: detailedCart.promotions.map((p) => p?.id).filter(Boolean) as string[] promo_id: detailedCart.promotions.map((p) => p?.id).filter(Boolean) as string[],
} },
}) })
// Validate that if a tier promotion is applied, the customer belongs to that tier // Validate that if a tier promotion is applied, the customer belongs to that tier
@@ -68761,7 +68761,7 @@ class TierModuleService extends MedusaService({
// ... // ...
async calculateNextTierUpgrade( async calculateNextTierUpgrade(
currencyCode: string, currencyCode: string,
currentPurchaseValue: number, currentPurchaseValue: number
) { ) {
const rules = await this.listTierRules( const rules = await this.listTierRules(
{ {
@@ -68866,7 +68866,7 @@ export async function GET(
// Get currency code from cart or region context // Get currency code from cart or region context
// Try to get from cart first, then region // Try to get from cart first, then region
let regionId = req.validatedQuery.region_id const regionId = req.validatedQuery.region_id
// Calculate total purchase value // Calculate total purchase value
const { data: orders } = await query.graph({ const { data: orders } = await query.graph({
@@ -68879,7 +68879,7 @@ export async function GET(
$nin: [ $nin: [
OrderStatus.CANCELED, OrderStatus.CANCELED,
OrderStatus.DRAFT, OrderStatus.DRAFT,
] ],
}, },
}, },
}) })
@@ -68911,7 +68911,7 @@ export async function GET(
const currentTier = customer.tier || null const currentTier = customer.tier || null
// Determine next tier upgrade // Determine next tier upgrade
let nextTierUpgrade = await tierModuleService.calculateNextTierUpgrade( const nextTierUpgrade = await tierModuleService.calculateNextTierUpgrade(
currencyCode as string, currencyCode as string,
totalPurchaseValue totalPurchaseValue
) )
@@ -69018,9 +69018,9 @@ export const retrieveCustomerNextTier =
const authHeaders = await getAuthHeaders() const authHeaders = await getAuthHeaders()
const region = await getRegion(countryCode) const region = await getRegion(countryCode)
if (!region) return null if (!region) {return null}
if (!authHeaders) return null if (!authHeaders) {return null}
const headers = { const headers = {
...authHeaders, ...authHeaders,
@@ -69037,7 +69037,7 @@ export const retrieveCustomerNextTier =
next, next,
query: { query: {
region_id: region.id, region_id: region.id,
} },
}) })
.then((data) => data) .then((data) => data)
.catch(() => null) .catch(() => null)
@@ -94107,7 +94107,7 @@ To create the workflow, create the file `src/workflows/sync-products.ts` with th
import { import {
createWorkflow, createWorkflow,
transform, transform,
WorkflowResponse WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "@medusajs/medusa/core-flows" import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products" import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products"
@@ -94123,11 +94123,11 @@ export const syncProductsWorkflow = createWorkflow(
"sync-products", "sync-products",
({ filters, limit, offset }: SyncProductsWorkflowInput) => { ({ filters, limit, offset }: SyncProductsWorkflowInput) => {
const productFilters = transform({ const productFilters = transform({
filters filters,
}, (data) => { }, (data) => {
return { return {
status: ProductStatus.PUBLISHED, status: ProductStatus.PUBLISHED,
...data.filters ...data.filters,
} }
}) })
const { data, metadata } = useQueryGraphStep({ const { data, metadata } = useQueryGraphStep({
@@ -101971,7 +101971,7 @@ To create the workflow, create the file `src/workflows/sync-products.ts` with th
import { import {
createWorkflow, createWorkflow,
transform, transform,
WorkflowResponse WorkflowResponse,
} from "@medusajs/framework/workflows-sdk" } from "@medusajs/framework/workflows-sdk"
import { useQueryGraphStep } from "@medusajs/medusa/core-flows" import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products" import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products"
@@ -101987,11 +101987,11 @@ export const syncProductsWorkflow = createWorkflow(
"sync-products", "sync-products",
({ filters, limit, offset }: SyncProductsWorkflowInput) => { ({ filters, limit, offset }: SyncProductsWorkflowInput) => {
const productFilters = transform({ const productFilters = transform({
filters filters,
}, (data) => { }, (data) => {
return { return {
status: ProductStatus.PUBLISHED, status: ProductStatus.PUBLISHED,
...data.filters ...data.filters,
} }
}) })
const { data, metadata } = useQueryGraphStep({ const { data, metadata } = useQueryGraphStep({
+13
View File
@@ -1,3 +1,16 @@
---
keywords:
- email
- mail
- medusa mail
- transactional email
- marketing email
- email service
- cloud email
- medusa cloud email
- medusa emails
---
import { CodeTabs, CodeTab, Prerequisites, InlineIcon } from "docs-ui" import { CodeTabs, CodeTab, Prerequisites, InlineIcon } from "docs-ui"
import { ChevronUpDown } from "@medusajs/icons" import { ChevronUpDown } from "@medusajs/icons"
+1 -1
View File
@@ -26,6 +26,6 @@ export const generatedEditDates = {
"app/billing/plans/page.mdx": "2025-10-08T14:49:27.009Z", "app/billing/plans/page.mdx": "2025-10-08T14:49:27.009Z",
"app/cache/page.mdx": "2025-11-12T14:37:24.809Z", "app/cache/page.mdx": "2025-11-12T14:37:24.809Z",
"app/deployments/troubleshooting/page.mdx": "2025-10-17T14:44:22.894Z", "app/deployments/troubleshooting/page.mdx": "2025-10-17T14:44:22.894Z",
"app/emails/page.mdx": "2025-11-12T15:41:36.777Z", "app/emails/page.mdx": "2025-11-26T11:07:58.083Z",
"app/emails/react-email/page.mdx": "2025-11-12T15:41:56.365Z" "app/emails/react-email/page.mdx": "2025-11-12T15:41:56.365Z"
} }