@mercurjs/docs 2.2.1 → 2.3.0-canary.1
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/content/home.mdx +107 -0
- package/content/learn/architecture.mdx +168 -83
- package/content/learn/introduction.mdx +161 -56
- package/content/learn/migration-to-2-0.mdx +187 -0
- package/content/learn/why-mercur.mdx +91 -0
- package/content/platform/attribute/concepts/attribute-types.mdx +59 -0
- package/content/platform/attribute/concepts/global-vs-inline.mdx +50 -0
- package/content/platform/attribute/concepts/variant-axes.mdx +61 -0
- package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +69 -0
- package/content/platform/attribute/guides/create-a-variant-axis.mdx +83 -0
- package/content/platform/attribute/guides/create-an-attribute.mdx +81 -0
- package/content/platform/attribute/overview.mdx +87 -0
- package/content/platform/attribute/reference/data-models.mdx +56 -0
- package/content/platform/attribute/reference/events.mdx +41 -0
- package/content/platform/attribute/reference/links.mdx +45 -0
- package/content/platform/attribute/reference/service.mdx +49 -0
- package/content/platform/attribute/reference/workflows.mdx +45 -0
- package/content/platform/catalog/concepts/master-products.mdx +54 -0
- package/content/platform/catalog/concepts/product-seller-allowlist.mdx +48 -0
- package/content/platform/catalog/concepts/status-lifecycle.mdx +58 -0
- package/content/platform/catalog/concepts/variants-categories-collections.mdx +49 -0
- package/content/platform/catalog/guides/allowlist-stores.mdx +59 -0
- package/content/platform/catalog/guides/create-a-master-product.mdx +70 -0
- package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +79 -0
- package/content/platform/catalog/overview.mdx +90 -0
- package/content/platform/catalog/reference/data-models.mdx +66 -0
- package/content/platform/catalog/reference/events.mdx +41 -0
- package/content/platform/catalog/reference/links.mdx +44 -0
- package/content/platform/catalog/reference/service.mdx +52 -0
- package/content/platform/catalog/reference/workflows.mdx +40 -0
- package/content/platform/commission/concepts/order-commission-lines.mdx +65 -0
- package/content/platform/commission/concepts/rule-matching.mdx +86 -0
- package/content/platform/commission/concepts/rules-and-rates.mdx +84 -0
- package/content/platform/commission/guides/batch-update-rules.mdx +58 -0
- package/content/platform/commission/guides/create-a-rate.mdx +72 -0
- package/content/platform/commission/guides/refresh-order-commission-lines.mdx +55 -0
- package/content/platform/commission/overview.mdx +86 -0
- package/content/platform/commission/reference/data-models.mdx +75 -0
- package/content/platform/commission/reference/events.mdx +58 -0
- package/content/platform/commission/reference/links.mdx +45 -0
- package/content/platform/commission/reference/service.mdx +51 -0
- package/content/platform/commission/reference/workflows.mdx +40 -0
- package/content/platform/offer/concepts/pricing-and-inventory.mdx +72 -0
- package/content/platform/offer/concepts/shipping.mdx +48 -0
- package/content/platform/offer/concepts/what-is-an-offer.mdx +65 -0
- package/content/platform/offer/guides/bulk-create-offers.mdx +84 -0
- package/content/platform/offer/guides/create-an-offer.mdx +83 -0
- package/content/platform/offer/guides/manage-offer-inventory.mdx +53 -0
- package/content/platform/offer/overview.mdx +84 -0
- package/content/platform/offer/reference/data-models.mdx +56 -0
- package/content/platform/offer/reference/events.mdx +39 -0
- package/content/platform/offer/reference/links.mdx +60 -0
- package/content/platform/offer/reference/service.mdx +53 -0
- package/content/platform/offer/reference/workflows.mdx +38 -0
- package/content/platform/order-group/concepts/computed-totals.mdx +59 -0
- package/content/platform/order-group/concepts/order-splitting.mdx +61 -0
- package/content/platform/order-group/concepts/the-order-group.mdx +64 -0
- package/content/platform/order-group/guides/list-order-groups.mdx +67 -0
- package/content/platform/order-group/guides/retrieve-an-order-group.mdx +63 -0
- package/content/platform/order-group/guides/split-a-cart.mdx +58 -0
- package/content/platform/order-group/overview.mdx +83 -0
- package/content/platform/order-group/reference/data-models.mdx +40 -0
- package/content/platform/order-group/reference/events.mdx +37 -0
- package/content/platform/order-group/reference/links.mdx +45 -0
- package/content/platform/order-group/reference/service.mdx +50 -0
- package/content/platform/order-group/reference/workflows.mdx +39 -0
- package/content/platform/payout/concepts/account-lifecycle.mdx +75 -0
- package/content/platform/payout/concepts/accounts-and-onboarding.mdx +70 -0
- package/content/platform/payout/concepts/payout-pipeline.mdx +99 -0
- package/content/platform/payout/guides/create-a-payout-account.mdx +59 -0
- package/content/platform/payout/guides/process-a-provider-webhook.mdx +74 -0
- package/content/platform/payout/guides/start-provider-onboarding.mdx +50 -0
- package/content/platform/payout/overview.mdx +86 -0
- package/content/platform/payout/reference/data-models.mdx +61 -0
- package/content/platform/payout/reference/events.mdx +48 -0
- package/content/platform/payout/reference/links.mdx +36 -0
- package/content/platform/payout/reference/service.mdx +53 -0
- package/content/platform/payout/reference/workflows.mdx +32 -0
- package/content/platform/product-edit/concepts/change-actions.mdx +66 -0
- package/content/platform/product-edit/concepts/change-pipeline.mdx +69 -0
- package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +66 -0
- package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +76 -0
- package/content/platform/product-edit/guides/edit-a-product.mdx +74 -0
- package/content/platform/product-edit/guides/request-a-revision.mdx +54 -0
- package/content/platform/product-edit/overview.mdx +85 -0
- package/content/platform/product-edit/reference/data-models.mdx +65 -0
- package/content/platform/product-edit/reference/events.mdx +47 -0
- package/content/platform/product-edit/reference/links.mdx +39 -0
- package/content/platform/product-edit/reference/service.mdx +43 -0
- package/content/platform/product-edit/reference/workflows.mdx +49 -0
- package/content/platform/review/concepts/product-vs-seller-reviews.mdx +63 -0
- package/content/platform/review/concepts/ratings-and-moderation.mdx +64 -0
- package/content/platform/review/concepts/the-review-model.mdx +56 -0
- package/content/platform/review/guides/compute-aggregate-ratings.mdx +57 -0
- package/content/platform/review/guides/create-a-review.mdx +55 -0
- package/content/platform/review/guides/moderate-a-review.mdx +58 -0
- package/content/platform/review/guides/respond-to-a-review.mdx +61 -0
- package/content/platform/review/overview.mdx +87 -0
- package/content/platform/review/reference/data-models.mdx +36 -0
- package/content/platform/review/reference/events.mdx +61 -0
- package/content/platform/review/reference/links.mdx +43 -0
- package/content/platform/review/reference/service.mdx +54 -0
- package/content/platform/review/reference/workflows.mdx +31 -0
- package/content/platform/store/concepts/lifecycle.mdx +62 -0
- package/content/platform/store/concepts/store-entity.mdx +53 -0
- package/content/platform/store/concepts/team.mdx +50 -0
- package/content/platform/store/guides/create-a-store.mdx +55 -0
- package/content/platform/store/guides/manage-the-team.mdx +55 -0
- package/content/platform/store/guides/moderate-a-store.mdx +59 -0
- package/content/platform/store/overview.mdx +86 -0
- package/content/platform/store/reference/data-models.mdx +89 -0
- package/content/platform/store/reference/events.mdx +43 -0
- package/content/platform/store/reference/links.mdx +71 -0
- package/content/platform/store/reference/service.mdx +51 -0
- package/content/platform/store/reference/workflows.mdx +35 -0
- package/content/references/api/admin/commission-rates/create-commission-rate.mdx +1 -1
- package/content/references/api/admin/commission-rates/list-commission-rates.mdx +2 -2
- package/content/references/api/admin/commission-rates/update-commission-rate.mdx +1 -1
- package/content/references/api/admin/offers/batch-create-offers.mdx +3 -3
- package/content/references/api/admin/order-groups/list-order-groups.mdx +1 -1
- package/content/references/api/admin/product-attributes/create-attribute-value.mdx +2 -2
- package/content/references/api/admin/product-attributes/create-product-attribute.mdx +1 -1
- package/content/references/api/admin/product-attributes/update-product-attribute.mdx +1 -1
- package/content/references/api/admin/product-changes/confirm-product-change.mdx +1 -1
- package/content/references/api/admin/products/batch-product-attributes.mdx +1 -1
- package/content/references/api/admin/products/create-product.mdx +1 -1
- package/content/references/api/admin/products/preview-product.mdx +1 -1
- package/content/references/api/admin.mdx +4 -5
- package/content/references/api/conventions.mdx +9 -7
- package/content/references/api/store/carts/add-line-item.mdx +1 -1
- package/content/references/api/store/offers/list-offers.mdx +1 -1
- package/content/references/api/store/order-groups/list-order-groups.mdx +1 -1
- package/content/references/api/store.mdx +4 -13
- package/content/references/api/vendor/members/accept-member-invite.mdx +1 -1
- package/content/references/api/vendor/offers/batch-create-offers.mdx +4 -0
- package/content/references/api/vendor/offers/batch-offer-inventory-items.mdx +2 -0
- package/content/references/api/vendor/offers/create-offer.mdx +13 -1
- package/content/references/api/vendor/offers/list-offers.mdx +4 -0
- package/content/references/api/vendor/offers/retrieve-offer.mdx +4 -0
- package/content/references/api/vendor/offers/update-offer.mdx +12 -0
- package/content/references/api/vendor/payout-accounts/create-onboarding.mdx +1 -1
- package/content/references/api/vendor/products/batch-product-attributes.mdx +1 -1
- package/content/references/api/vendor/products/create-product-variant.mdx +1 -1
- package/content/references/api/vendor/products/create-product.mdx +1 -1
- package/content/references/api/vendor/products/delete-product.mdx +1 -1
- package/content/references/api/vendor/products/update-product.mdx +1 -1
- package/content/references/api/vendor/sellers/create-seller.mdx +2 -2
- package/content/references/api/vendor/sellers/list-sellers.mdx +1 -1
- package/content/references/api/vendor.mdx +6 -5
- package/content/references/configuration.mdx +16 -33
- package/content/references/overview.mdx +34 -52
- package/content/references/panel-extensions/create-page.mdx +194 -0
- package/content/references/panel-extensions/custom-fields.mdx +256 -0
- package/content/references/panel-extensions/overview.mdx +102 -0
- package/content/references/panel-extensions/widgets.mdx +212 -0
- package/content/resources/ai/mcp.mdx +2 -2
- package/content/resources/ai/overview.mdx +21 -16
- package/content/resources/ai/skills.mdx +67 -0
- package/content/resources/best-practices/api-routes.mdx +55 -43
- package/content/resources/best-practices/custom-fields.mdx +116 -92
- package/content/resources/best-practices/frontend.mdx +62 -50
- package/content/resources/best-practices/module-links.mdx +48 -34
- package/content/resources/best-practices/modules.mdx +53 -27
- package/content/resources/best-practices/overview.mdx +45 -17
- package/content/resources/best-practices/subscribers-and-jobs.mdx +37 -24
- package/content/resources/best-practices/types.mdx +38 -23
- package/content/resources/best-practices/workflows.mdx +33 -21
- package/content/resources/customization/custom-fields.mdx +15 -15
- package/content/resources/customization/extend-a-workflow.mdx +7 -4
- package/content/resources/customization/extending-panels.mdx +55 -52
- package/content/resources/deployment/medusa-cloud.mdx +21 -20
- package/content/resources/deployment/self-host.mdx +123 -0
- package/content/resources/integrations/overview.mdx +38 -0
- package/content/resources/integrations/stripe-connect.mdx +39 -38
- package/content/resources/tutorials/add-a-block.mdx +25 -18
- package/content/resources/tutorials/add-a-widget.mdx +32 -23
- package/content/resources/tutorials/add-order-detail-button.mdx +33 -20
- package/content/resources/tutorials/attributes-and-variant-axes.mdx +28 -27
- package/content/resources/tutorials/build-a-block.mdx +26 -15
- package/content/resources/tutorials/custom-api-route.mdx +32 -20
- package/content/resources/tutorials/custom-panel-page.mdx +21 -12
- package/content/resources/tutorials/customize-navigation.mdx +30 -23
- package/content/resources/tutorials/extend-forms-and-tables.mdx +36 -28
- package/content/resources/tutorials/extend-onboarding.mdx +38 -35
- package/content/resources/tutorials/master-products-and-offers.mdx +28 -23
- package/content/telemetry.mdx +3 -3
- package/content/user-guide/admin/attributes/how-tos/create-an-attribute.mdx +64 -0
- package/content/user-guide/admin/attributes/how-tos/manage-possible-values.mdx +40 -0
- package/content/user-guide/admin/attributes/overview.mdx +22 -0
- package/content/user-guide/admin/commissions/how-tos/create-a-commission-rule.mdx +63 -0
- package/content/user-guide/admin/commissions/how-tos/edit-the-global-commission.mdx +48 -0
- package/content/user-guide/admin/commissions/how-tos/manage-a-commission-rule.mdx +45 -0
- package/content/user-guide/admin/commissions/overview.mdx +25 -0
- package/content/user-guide/admin/overview.mdx +20 -12
- package/content/user-guide/admin/product-requests/how-tos/review-a-new-product.mdx +58 -0
- package/content/user-guide/admin/product-requests/how-tos/review-a-product-edit.mdx +48 -0
- package/content/user-guide/admin/product-requests/overview.mdx +25 -0
- package/content/user-guide/vendor/offers/how-tos/create-an-offer.mdx +59 -0
- package/content/user-guide/vendor/offers/how-tos/update-prices-and-stock.mdx +40 -0
- package/content/user-guide/vendor/offers/overview.mdx +22 -0
- package/content/user-guide/vendor/onboarding.mdx +79 -0
- package/content/user-guide/vendor/orders/how-tos/fulfill-an-order.mdx +49 -0
- package/content/user-guide/vendor/orders/how-tos/mark-an-order-as-delivered.mdx +33 -0
- package/content/user-guide/vendor/orders/how-tos/process-a-return.mdx +42 -0
- package/content/user-guide/vendor/orders/how-tos/refund-an-order.mdx +38 -0
- package/content/user-guide/vendor/orders/how-tos/ship-an-order.mdx +40 -0
- package/content/user-guide/vendor/orders/overview.mdx +31 -0
- package/content/user-guide/vendor/overview.mdx +23 -12
- package/content/user-guide/vendor/products/how-tos/edit-a-product.mdx +44 -0
- package/content/user-guide/vendor/products/how-tos/submit-a-product.mdx +63 -0
- package/content/user-guide/vendor/products/overview.mdx +22 -0
- package/llms.txt +176 -142
- package/package.json +1 -1
- package/content/learn/concepts.mdx +0 -84
- package/content/learn/installation.mdx +0 -117
- package/content/learn/mirakl-alternative.mdx +0 -86
- package/content/migration/from-1-x-to-2-0.mdx +0 -152
- package/content/migration/from-2-0-to-2-1.mdx +0 -105
- package/content/migration/overview.mdx +0 -58
- package/content/references/api/store/search/search.mdx +0 -136
- package/content/references/modules/commission.mdx +0 -106
- package/content/references/modules/custom-fields.mdx +0 -45
- package/content/references/modules/media.mdx +0 -55
- package/content/references/modules/offer.mdx +0 -64
- package/content/references/modules/payout.mdx +0 -121
- package/content/references/modules/product-attribute.mdx +0 -111
- package/content/references/modules/product-edit.mdx +0 -80
- package/content/references/modules/search.mdx +0 -112
- package/content/references/modules/seller.mdx +0 -175
- package/content/references/panel-extension-api.mdx +0 -337
- package/content/references/workflows/cart/add-seller-shipping-method-to-cart.mdx +0 -48
- package/content/references/workflows/cart/complete-cart-with-split-orders.mdx +0 -36
- package/content/references/workflows/cart/list-seller-shipping-options-for-cart.mdx +0 -39
- package/content/references/workflows/cart/update-cart-seller-promotions.mdx +0 -42
- package/content/references/workflows/commission/batch-commission-rules.mdx +0 -49
- package/content/references/workflows/commission/create-commission-rates.mdx +0 -41
- package/content/references/workflows/commission/delete-commission-rates.mdx +0 -34
- package/content/references/workflows/commission/refresh-order-commission-lines.mdx +0 -30
- package/content/references/workflows/commission/update-commission-rates.mdx +0 -35
- package/content/references/workflows/media/set-category-images.mdx +0 -41
- package/content/references/workflows/media/set-collection-images.mdx +0 -41
- package/content/references/workflows/member/accept-member-invite.mdx +0 -33
- package/content/references/workflows/member/add-seller-member.mdx +0 -30
- package/content/references/workflows/member/create-member-invites.mdx +0 -34
- package/content/references/workflows/member/delete-member-invite.mdx +0 -24
- package/content/references/workflows/member/remove-seller-member.mdx +0 -28
- package/content/references/workflows/member/resend-member-invite.mdx +0 -28
- package/content/references/workflows/member/update-member-role.mdx +0 -28
- package/content/references/workflows/member/update-member.mdx +0 -35
- package/content/references/workflows/offer/batch-offer-inventory-items.mdx +0 -62
- package/content/references/workflows/offer/create-offers.mdx +0 -65
- package/content/references/workflows/offer/delete-offers.mdx +0 -35
- package/content/references/workflows/offer/update-offers.mdx +0 -53
- package/content/references/workflows/order/cancel-order-fulfillment.mdx +0 -34
- package/content/references/workflows/order/confirm-claim-request.mdx +0 -25
- package/content/references/workflows/order/confirm-exchange-request.mdx +0 -25
- package/content/references/workflows/order/confirm-order-edit-request.mdx +0 -25
- package/content/references/workflows/order/confirm-return-receive.mdx +0 -25
- package/content/references/workflows/order/create-order-fulfillment.mdx +0 -45
- package/content/references/workflows/order-group/get-order-group-detail.mdx +0 -29
- package/content/references/workflows/order-group/get-order-groups-list.mdx +0 -38
- package/content/references/workflows/overview.mdx +0 -72
- package/content/references/workflows/payout/create-onboarding.mdx +0 -36
- package/content/references/workflows/payout/create-payout-account.mdx +0 -33
- package/content/references/workflows/payout/create-payout.mdx +0 -30
- package/content/references/workflows/payout/process-payout-for-webhook.mdx +0 -34
- package/content/references/workflows/product/confirm-products.mdx +0 -48
- package/content/references/workflows/product/create-products.mdx +0 -63
- package/content/references/workflows/product/link-sellers-to-product-category.mdx +0 -40
- package/content/references/workflows/product/link-sellers-to-product.mdx +0 -40
- package/content/references/workflows/product/reject-product.mdx +0 -48
- package/content/references/workflows/product/request-product-change.mdx +0 -48
- package/content/references/workflows/product-attribute/add-product-attributes-to-product.mdx +0 -49
- package/content/references/workflows/product-attribute/create-and-link-product-attributes-to-product.mdx +0 -46
- package/content/references/workflows/product-attribute/create-product-attribute-values.mdx +0 -43
- package/content/references/workflows/product-attribute/create-product-attributes.mdx +0 -56
- package/content/references/workflows/product-attribute/delete-product-attribute-values.mdx +0 -30
- package/content/references/workflows/product-attribute/delete-product-attributes.mdx +0 -30
- package/content/references/workflows/product-attribute/remove-product-attributes-from-product.mdx +0 -29
- package/content/references/workflows/product-attribute/update-product-attribute-values.mdx +0 -44
- package/content/references/workflows/product-attribute/update-product-attributes-on-product.mdx +0 -41
- package/content/references/workflows/product-attribute/update-product-attributes.mdx +0 -48
- package/content/references/workflows/product-attribute/upsert-product-attribute-values.mdx +0 -43
- package/content/references/workflows/product-edit/auto-confirm-product-change.mdx +0 -39
- package/content/references/workflows/product-edit/cancel-product-change.mdx +0 -49
- package/content/references/workflows/product-edit/confirm-product-change.mdx +0 -57
- package/content/references/workflows/product-edit/create-product-change.mdx +0 -72
- package/content/references/workflows/product-edit/reject-product-change.mdx +0 -54
- package/content/references/workflows/product-edit/stage-product-change.mdx +0 -75
- package/content/references/workflows/seller/approve-seller.mdx +0 -36
- package/content/references/workflows/seller/create-seller-account.mdx +0 -59
- package/content/references/workflows/seller/create-seller-defaults.mdx +0 -22
- package/content/references/workflows/seller/create-sellers.mdx +0 -65
- package/content/references/workflows/seller/delete-seller-professional-details.mdx +0 -37
- package/content/references/workflows/seller/delete-sellers.mdx +0 -24
- package/content/references/workflows/seller/invite-seller.mdx +0 -28
- package/content/references/workflows/seller/suspend-seller.mdx +0 -37
- package/content/references/workflows/seller/terminate-seller.mdx +0 -37
- package/content/references/workflows/seller/unsuspend-seller.mdx +0 -36
- package/content/references/workflows/seller/unterminate-seller.mdx +0 -36
- package/content/references/workflows/seller/update-seller-address.mdx +0 -55
- package/content/references/workflows/seller/update-seller-payment-details.mdx +0 -52
- package/content/references/workflows/seller/update-seller-professional-details.mdx +0 -48
- package/content/references/workflows/seller/update-sellers.mdx +0 -57
- package/content/resources/ai/llms.mdx +0 -74
- package/content/resources/integrations/notifications.mdx +0 -39
- package/content/resources/integrations/search.mdx +0 -122
- package/content/resources/tutorials/configure-commissions.mdx +0 -127
- package/content/resources/tutorials/first-marketplace.mdx +0 -45
- package/content/resources/tutorials/handle-product-requests.mdx +0 -80
- package/content/resources/tutorials/import-export-products.mdx +0 -96
- package/content/resources/tutorials/seller-payouts-stripe.mdx +0 -89
- package/content/resources/tutorials/store-setup-checklist.mdx +0 -214
- package/content/tools/api-client.mdx +0 -155
- package/content/tools/cli.mdx +0 -196
- package/content/tools/dashboard-sdk.mdx +0 -35
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Customize
|
|
3
|
-
|
|
2
|
+
title: "How to Customize Navigation"
|
|
3
|
+
sidebarTitle: "Customize Navigation"
|
|
4
|
+
description: "Reorder, hide, relabel, and re-parent the panel's built-in sidebar items from a single _navigation.ts file."
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Reshape the built-in sidebar without replacing it. You author one host-owned file, `src/_navigation.ts`, and it reorders, hides, relabels, and re-parents the built-in items.
|
|
8
|
+
|
|
9
|
+
The sidebar ships a fixed set of items such as Orders, Products, and Customers. `_navigation.ts` is the single source of truth for their shape. It overrides existing items only, so a new item still comes from a page you add.
|
|
7
10
|
|
|
8
11
|
<Info>
|
|
9
|
-
**When to use this vs. a `config` export.** New pages you add via [drop-in routes](/rc/resources/tutorials/custom-panel-page) place their own sidebar item through `defineRouteConfig({ label, rank, nested })`. `_navigation.ts` is for the items you *didn't* create
|
|
12
|
+
**When to use this vs. a `config` export.** New pages you add via [drop-in routes](/rc/resources/tutorials/custom-panel-page) place their own sidebar item through `defineRouteConfig({ label, rank, nested })`. `_navigation.ts` is for the items you *didn't* create, the built-in ones. The two layer cleanly: custom routes place themselves, and `_navigation.ts` reshapes the built-ins.
|
|
10
13
|
</Info>
|
|
11
14
|
|
|
12
15
|
## What you'll build
|
|
13
16
|
|
|
14
17
|
A vendor sidebar with Orders pinned to the top, Price Lists hidden, and Campaigns moved under Orders.
|
|
15
18
|
|
|
16
|
-
## Register the typed targets
|
|
19
|
+
## Register the typed targets
|
|
17
20
|
|
|
18
|
-
Nav item ids are typed and generated per panel. Register them once with a single ambient reference in your app's `src
|
|
21
|
+
Nav item ids are typed and generated per panel. Register them once with a single ambient reference in your app's `src`. The `create-mercur-app` scaffold already ships this file.
|
|
19
22
|
|
|
20
23
|
```typescript apps/vendor/src/extension-targets.d.ts
|
|
21
24
|
/// <reference types="@mercurjs/vendor/extension-targets" />
|
|
@@ -27,7 +30,7 @@ With it present, `id` and `nested` autocomplete and an unknown id fails `tsc`.
|
|
|
27
30
|
|
|
28
31
|
<Steps>
|
|
29
32
|
<Step title="Create src/_navigation.ts">
|
|
30
|
-
The file is host-owned and underscore-prefixed. Default-export a `defineNavigationConfig` with an `items` array of overrides
|
|
33
|
+
The file is host-owned and underscore-prefixed. Default-export a `defineNavigationConfig` with an `items` array of overrides.
|
|
31
34
|
|
|
32
35
|
```ts apps/vendor/src/_navigation.ts
|
|
33
36
|
import { defineNavigationConfig } from "@mercurjs/dashboard-sdk"
|
|
@@ -42,21 +45,25 @@ With it present, `id` and `nested` autocomplete and an unknown id fails `tsc`.
|
|
|
42
45
|
```
|
|
43
46
|
</Step>
|
|
44
47
|
<Step title="Know the override fields">
|
|
45
|
-
Each entry targets one built-in item by its stable `id
|
|
48
|
+
Each entry targets one built-in item by its stable `id`.
|
|
46
49
|
|
|
47
50
|
| Field | Type | Effect |
|
|
48
51
|
|-------|------|--------|
|
|
49
|
-
| `id` | `NavItemId` | **Required.** The built-in item to override
|
|
50
|
-
| `rank` | `number` | Order within its parent
|
|
51
|
-
| `hidden` | `boolean` | Remove it from the sidebar |
|
|
52
|
-
| `label` | `string` | Relabel
|
|
53
|
-
| `icon` | `ComponentType` | Replace its icon |
|
|
54
|
-
| `nested` | `NavParentId \| null` | Re-parent under another top-level item
|
|
55
|
-
|
|
56
|
-
Both `id` and `nested` are checked against the panel's generated `NavItemRegistry`
|
|
52
|
+
| `id` | `NavItemId` | **Required.** The built-in item to override, top-level or nested. |
|
|
53
|
+
| `rank` | `number` | Order within its parent, lower first. |
|
|
54
|
+
| `hidden` | `boolean` | Remove it from the sidebar. |
|
|
55
|
+
| `label` | `string` | Relabel with an i18n key or literal. |
|
|
56
|
+
| `icon` | `ComponentType` | Replace its icon. |
|
|
57
|
+
| `nested` | `NavParentId \| null` | Re-parent under another top-level item. `null` promotes a nested item to top level. |
|
|
58
|
+
|
|
59
|
+
Both `id` and `nested` are checked against the panel's generated `NavItemRegistry` and `NavParentRegistry`.
|
|
57
60
|
</Step>
|
|
58
61
|
<Step title="Reload the panel">
|
|
59
|
-
Open the vendor portal
|
|
62
|
+
Open the vendor portal. Orders sits at the top, Price Lists is gone from the menu, and Campaigns now appears under Orders.
|
|
63
|
+
|
|
64
|
+
<Note>
|
|
65
|
+
The route for a hidden item stays reachable directly by URL unless you also remove it.
|
|
66
|
+
</Note>
|
|
60
67
|
</Step>
|
|
61
68
|
</Steps>
|
|
62
69
|
|
|
@@ -78,23 +85,23 @@ export default defineNavigationConfig({
|
|
|
78
85
|
1. The top-level order reflects your `rank` values, with `orders` first.
|
|
79
86
|
2. `price-lists` no longer appears in the sidebar.
|
|
80
87
|
3. `campaigns` renders as a child under Orders.
|
|
81
|
-
4. Set `id: "not-an-item"
|
|
82
|
-
5. Delete `_navigation.ts
|
|
88
|
+
4. Set `id: "not-an-item"`. `bun run lint` (tsc) fails against `NavItemRegistry`.
|
|
89
|
+
5. Delete `_navigation.ts`. The default sidebar returns.
|
|
83
90
|
|
|
84
91
|
## FAQ
|
|
85
92
|
|
|
86
93
|
<AccordionGroup>
|
|
87
94
|
<Accordion title="Can an installed block reorder the sidebar?">
|
|
88
|
-
No. Navigation is deliberately host-only
|
|
95
|
+
No. Navigation is deliberately host-only. Blocks can ship pages, widgets, and custom fields, but the sidebar order stays a single source of truth in your app's `_navigation.ts`.
|
|
89
96
|
</Accordion>
|
|
90
97
|
<Accordion title="What ids can I target?">
|
|
91
|
-
Any built-in item, top-level or nested, by its own id
|
|
98
|
+
Any built-in item, top-level or nested, by its own id, such as `orders`, `products`, `categories`, `collections`, `campaigns`, or `customer-groups`. Let your editor autocomplete `id:` against `NavItemId`. The full set is generated into your panel's `extension-targets.d.ts`.
|
|
92
99
|
</Accordion>
|
|
93
100
|
<Accordion title="Does this work in the admin panel too?">
|
|
94
|
-
Yes
|
|
101
|
+
Yes. Drop `src/_navigation.ts` in the admin app and reference `@mercurjs/admin/extension-targets`. Each panel ships its own nav id set.
|
|
95
102
|
</Accordion>
|
|
96
103
|
<Accordion title="How do I add a brand-new sidebar item?">
|
|
97
|
-
That's a [drop-in route](/rc/resources/tutorials/custom-panel-page) with a `config` export
|
|
104
|
+
That's a [drop-in route](/rc/resources/tutorials/custom-panel-page) with a `config` export. `_navigation.ts` only reshapes built-in items, it doesn't create routes.
|
|
98
105
|
</Accordion>
|
|
99
106
|
</AccordionGroup>
|
|
100
107
|
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Extend
|
|
3
|
-
|
|
2
|
+
title: "How to Extend Forms and Tables"
|
|
3
|
+
sidebarTitle: "Extend Forms & Tables"
|
|
4
|
+
description: "Add validated fields, detail-section displays, and list columns to a built-in model from a single file with defineCustomFieldsConfig."
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
`defineCustomFieldsConfig` is Mercur's model-scoped extension surface
|
|
7
|
+
`defineCustomFieldsConfig` is Mercur's model-scoped extension surface. From one file per model you add validated fields to built-in create and edit forms, replace, remove, or add fields in detail sections, and add columns to the list table. Everything wires into the built-in page and stays typed against the model's generated registry.
|
|
7
8
|
|
|
8
9
|
<Info>
|
|
9
|
-
**UI, not schema.** This helper is a
|
|
10
|
+
**UI, not schema.** This helper is a panel surface. It renders, validates, and displays fields. It does not create database columns. To store extra data, use the backend [Custom Fields module](/rc/resources/customization/custom-fields) or your own API route or workflow. In the MVP, panel custom fields for `product` are submitted under `additional_data` and persisted onto the product's `metadata`.
|
|
10
11
|
</Info>
|
|
11
12
|
|
|
12
13
|
## What you'll build
|
|
13
14
|
|
|
14
|
-
An `ERP ID` field on the vendor product edit form, shown in the product's detail section and as a list-table column
|
|
15
|
+
An `ERP ID` field on the vendor product edit form, shown in the product's detail section and as a list-table column, all from a single `src/custom-fields/product.tsx`.
|
|
15
16
|
|
|
16
|
-
## Register the typed targets
|
|
17
|
+
## Register the typed targets
|
|
17
18
|
|
|
18
|
-
Models, form zones, display zones, and built-in field ids are typed per panel.
|
|
19
|
+
Models, form zones, display zones, and built-in field ids are typed per panel. You register them once, and `create-mercur-app` ships this reference for you.
|
|
19
20
|
|
|
20
21
|
```typescript apps/vendor/src/extension-targets.d.ts
|
|
21
22
|
/// <reference types="@mercurjs/vendor/extension-targets" />
|
|
@@ -25,7 +26,7 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
25
26
|
|
|
26
27
|
<Steps>
|
|
27
28
|
<Step title="Create the model file">
|
|
28
|
-
Drop `src/custom-fields/<model>.tsx` and default-export a `defineCustomFieldsConfig`. `createFormHelper`
|
|
29
|
+
Drop `src/custom-fields/<model>.tsx` and default-export a `defineCustomFieldsConfig`. `createFormHelper` from `@mercurjs/dashboard-shared` turns a Zod schema into an input type plus validation.
|
|
29
30
|
|
|
30
31
|
```tsx apps/vendor/src/custom-fields/product.tsx
|
|
31
32
|
import { defineCustomFieldsConfig } from "@mercurjs/dashboard-sdk"
|
|
@@ -53,10 +54,11 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
53
54
|
})
|
|
54
55
|
```
|
|
55
56
|
</Step>
|
|
57
|
+
|
|
56
58
|
<Step title="Add a detail-section display">
|
|
57
|
-
`displays[]` targets a detail-page section by its `zone` id. Keyed by field `id`, an entry
|
|
59
|
+
`displays[]` targets a detail-page section by its `zone` id. Keyed by field `id`, an entry adds, replaces, or removes a field.
|
|
58
60
|
|
|
59
|
-
```tsx
|
|
61
|
+
```tsx apps/vendor/src/custom-fields/product.tsx
|
|
60
62
|
import { Text } from "@medusajs/ui"
|
|
61
63
|
|
|
62
64
|
// ...inside defineCustomFieldsConfig:
|
|
@@ -64,7 +66,7 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
64
66
|
{
|
|
65
67
|
zone: "general",
|
|
66
68
|
fields: [
|
|
67
|
-
// ADD
|
|
69
|
+
// ADD: an unknown id appends a new read-only row
|
|
68
70
|
{
|
|
69
71
|
id: "erp_id",
|
|
70
72
|
component: ({ data }) => (
|
|
@@ -73,9 +75,9 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
73
75
|
</Text>
|
|
74
76
|
),
|
|
75
77
|
},
|
|
76
|
-
// REMOVE
|
|
78
|
+
// REMOVE: a built-in id + null hides the field
|
|
77
79
|
{ id: "subtitle", component: null },
|
|
78
|
-
// REPLACE
|
|
80
|
+
// REPLACE: a built-in id + component overrides its render
|
|
79
81
|
{
|
|
80
82
|
id: "handle",
|
|
81
83
|
component: ({ data }) => (
|
|
@@ -89,12 +91,15 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
89
91
|
],
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
<Tip>
|
|
95
|
+
Built-in field ids such as `subtitle`, `handle`, `status`, and `title` autocomplete from the panel's generated `CustomFieldsRegistry`. An unknown id is treated as an added row.
|
|
96
|
+
</Tip>
|
|
93
97
|
</Step>
|
|
98
|
+
|
|
94
99
|
<Step title="Add a list column">
|
|
95
|
-
The `list` block extends the model's list table
|
|
100
|
+
The `list` block extends the model's list table. Add or override columns by id, hide built-in columns, and reorder.
|
|
96
101
|
|
|
97
|
-
```tsx
|
|
102
|
+
```tsx apps/vendor/src/custom-fields/product.tsx
|
|
98
103
|
// ...inside defineCustomFieldsConfig:
|
|
99
104
|
list: {
|
|
100
105
|
columns: [
|
|
@@ -111,14 +116,15 @@ Models, form zones, display zones, and built-in field ids are typed per panel. R
|
|
|
111
116
|
},
|
|
112
117
|
```
|
|
113
118
|
</Step>
|
|
119
|
+
|
|
114
120
|
<Step title="Reload the panel">
|
|
115
|
-
Open the vendor portal. The product
|
|
121
|
+
Open the vendor portal. The product edit drawer shows the ERP ID field, validated on submit and persisted via `additional_data`. The detail general section shows the ERP ID row, with `subtitle` removed and `handle` re-rendered. The product list shows the ERP column.
|
|
116
122
|
</Step>
|
|
117
123
|
</Steps>
|
|
118
124
|
|
|
119
|
-
## The
|
|
125
|
+
## The createFormHelper surface
|
|
120
126
|
|
|
121
|
-
`createFormHelper<T>()` exposes a Zod-based surface that drives both the input type and its validation
|
|
127
|
+
`createFormHelper<T>()` exposes a Zod-based surface that drives both the input type and its validation.
|
|
122
128
|
|
|
123
129
|
```ts
|
|
124
130
|
const form = createFormHelper<T>()
|
|
@@ -133,11 +139,11 @@ form.define({
|
|
|
133
139
|
})
|
|
134
140
|
```
|
|
135
141
|
|
|
136
|
-
Fields render through the standard `Form.Field → Form.Item` chain
|
|
142
|
+
Fields render through the standard `Form.Field → Form.Item` chain, never a raw `Controller`. They participate in the existing `TabbedForm` and `RouteDrawer` submit and validation flow.
|
|
137
143
|
|
|
138
144
|
## Linked-module data
|
|
139
145
|
|
|
140
|
-
To read data from a linked module alongside the entity, declare it with `link
|
|
146
|
+
To read data from a linked module alongside the entity, declare it with `link`. Those relations are fetched with the entity and become available to columns and displays.
|
|
141
147
|
|
|
142
148
|
```ts
|
|
143
149
|
export default defineCustomFieldsConfig({
|
|
@@ -149,30 +155,32 @@ export default defineCustomFieldsConfig({
|
|
|
149
155
|
})
|
|
150
156
|
```
|
|
151
157
|
|
|
152
|
-
|
|
158
|
+
<Note>
|
|
159
|
+
The SDK derives the fetch query from `link` and merges it into the built-in query with the `+` and `-` convention. You never hand-write the field list.
|
|
160
|
+
</Note>
|
|
153
161
|
|
|
154
162
|
## Verify
|
|
155
163
|
|
|
156
164
|
1. The ERP ID field renders in the product edit drawer and validates on submit.
|
|
157
|
-
2. Saving persists the value
|
|
165
|
+
2. Saving persists the value, visible on reload, via `additional_data` to `metadata`.
|
|
158
166
|
3. The detail general section shows the ERP row, hides `subtitle`, and re-renders `handle`.
|
|
159
167
|
4. The product list shows the ERP column, hides `collection`, and reorders columns.
|
|
160
|
-
5. Set `zone: "nope"` in `forms
|
|
168
|
+
5. Set `zone: "nope"` in `forms`. `bun run lint` (tsc) fails against the model's registry.
|
|
161
169
|
|
|
162
170
|
## FAQ
|
|
163
171
|
|
|
164
172
|
<AccordionGroup>
|
|
165
173
|
<Accordion title="Which models and zones are available?">
|
|
166
|
-
Today: the `product` model in the vendor portal, with form zone `edit` and display zone `general`. The valid set per panel is generated into `CustomFieldsRegistry` in `extension-targets.d.ts
|
|
174
|
+
Today: the `product` model in the vendor portal, with form zone `edit` and display zone `general`. The valid set per panel is generated into `CustomFieldsRegistry` in `extension-targets.d.ts`. Autocomplete `model` and `zone` to see what's mounted.
|
|
167
175
|
</Accordion>
|
|
168
176
|
<Accordion title="Where is the value actually stored?">
|
|
169
|
-
In the MVP, product custom fields are submitted under `additional_data` and persisted onto `product.metadata`. `defineCustomFieldsConfig` itself doesn't create a column
|
|
177
|
+
In the MVP, product custom fields are submitted under `additional_data` and persisted onto `product.metadata`. `defineCustomFieldsConfig` itself doesn't create a column. For durable, queryable storage, model it with the backend [Custom Fields module](/rc/resources/customization/custom-fields) or a custom route or workflow.
|
|
170
178
|
</Accordion>
|
|
171
179
|
<Accordion title="Can I extend the onboarding wizard?">
|
|
172
|
-
That's the same helper with `zone: "onboarding"` and `tab` set to a wizard step id (vendor only). It's designed but not mounted in the current MVP
|
|
180
|
+
That's the same helper with `zone: "onboarding"` and `tab` set to a wizard step id (vendor only). It's designed but not mounted in the current MVP. The runtime host exists. The wizard mount is a follow-up.
|
|
173
181
|
</Accordion>
|
|
174
182
|
<Accordion title="Can a block ship custom fields?">
|
|
175
|
-
Yes
|
|
183
|
+
Yes. A [block](/rc/learn/blocks) can include `src/custom-fields/` files in its `vendor_ui` or `admin_ui` entry, aggregated like the host app's.
|
|
176
184
|
</Accordion>
|
|
177
185
|
</AccordionGroup>
|
|
178
186
|
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
|
|
2
|
+
title: "How to Extend Onboarding"
|
|
3
|
+
sidebarTitle: "Extend Onboarding"
|
|
4
|
+
description: "Add a field to the vendor store-setup surface, carry it through additional_data, and persist it from a workflow hook without forking core."
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Add a custom field to the vendor onboarding flow and store its value durably, end to end.
|
|
8
|
+
|
|
9
|
+
The vendor store-setup and onboarding surface is a widget zone, `seller.setup`, that renders the full `seller` object as its `data`. That makes onboarding a full extension seam. You drop a widget to add UI, carry the new value to the API on the built-in seller routes through `additional_data`, and persist it from a workflow hook. These are the same three layers you wire in plain Medusa, kept intact by Mercur.
|
|
7
10
|
|
|
8
11
|
<Info>
|
|
9
|
-
**Three layers, one flow.** The panel
|
|
12
|
+
**Three layers, one flow.** The panel, a `seller.setup` widget, renders and collects. The vendor seller route carries the value through `additional_data` with no core schema change. A `sellersUpdated` workflow hook persists it. Each layer is additive: nothing built-in is replaced.
|
|
10
13
|
</Info>
|
|
11
14
|
|
|
12
|
-
## What you
|
|
15
|
+
## What you build
|
|
13
16
|
|
|
14
|
-
A "Tax ID" prompt on the vendor store-setup surface. The vendor types a VAT number
|
|
17
|
+
A "Tax ID" prompt on the vendor store-setup surface. The vendor types a VAT number. It rides `additional_data` to `POST /vendor/sellers/:id`, and a workflow hook stores it durably through the [Custom Fields module](/rc/resources/customization/custom-fields).
|
|
15
18
|
|
|
16
|
-
## Register the typed targets
|
|
19
|
+
## Register the typed targets
|
|
17
20
|
|
|
18
|
-
Widget zones are typed ids the vendor panel generates from its own pages and ships as `@mercurjs/vendor/extension-targets`. Register them once
|
|
21
|
+
Widget zones are typed ids the vendor panel generates from its own pages and ships as `@mercurjs/vendor/extension-targets`. Register them once. `create-mercur-app` ships this file for you.
|
|
19
22
|
|
|
20
23
|
```typescript apps/vendor/src/extension-targets.d.ts
|
|
21
24
|
/// <reference types="@mercurjs/vendor/extension-targets" />
|
|
@@ -23,11 +26,11 @@ Widget zones are typed ids the vendor panel generates from its own pages and shi
|
|
|
23
26
|
|
|
24
27
|
With it present, `seller.setup` autocompletes and an invalid zone fails `tsc` instead of silently doing nothing.
|
|
25
28
|
|
|
26
|
-
##
|
|
29
|
+
## Render on the onboarding surface
|
|
27
30
|
|
|
28
31
|
<Steps>
|
|
29
32
|
<Step title="Add the store-setup widget">
|
|
30
|
-
Drop a file under `src/widgets/`. Export the component as the **default** and a `config` with `zone: "seller.setup.before"`. The zone hands your component the `seller` as `data
|
|
33
|
+
Drop a file under `src/widgets/`. Export the component as the **default** and a `config` with `zone: "seller.setup.before"`. The zone hands your component the `seller` as `data`.
|
|
31
34
|
|
|
32
35
|
```tsx apps/vendor/src/widgets/tax-id-setup.tsx
|
|
33
36
|
import "@mercurjs/vendor/extension-targets"
|
|
@@ -50,7 +53,7 @@ With it present, `seller.setup` autocompletes and an invalid zone fails `tsc` in
|
|
|
50
53
|
mutationFn: () =>
|
|
51
54
|
client.vendor.sellers.$id.mutate({
|
|
52
55
|
$id: seller!.id,
|
|
53
|
-
// additional_data is accepted on every vendor seller route
|
|
56
|
+
// additional_data is accepted on every vendor seller route.
|
|
54
57
|
// it never touches the built-in seller columns.
|
|
55
58
|
additional_data: { tax_id: taxId },
|
|
56
59
|
}),
|
|
@@ -94,26 +97,26 @@ With it present, `seller.setup` autocompletes and an invalid zone fails `tsc` in
|
|
|
94
97
|
```
|
|
95
98
|
</Step>
|
|
96
99
|
<Step title="Understand where it renders">
|
|
97
|
-
`seller.setup` is hosted in two places, both passing the same `seller` as `data
|
|
100
|
+
`seller.setup` is hosted in two places, both passing the same `seller` as `data`.
|
|
98
101
|
|
|
99
102
|
| Host | When it shows |
|
|
100
103
|
|------|---------------|
|
|
101
|
-
| The vendor shell (above the page outlet) | On top-level routes
|
|
104
|
+
| The vendor shell (above the page outlet) | On top-level routes (the dashboard "home" onboarding banner) |
|
|
102
105
|
| The store settings detail page | Always, above the store status banner |
|
|
103
106
|
|
|
104
|
-
A single widget file covers both. Multiple `seller.setup.before`
|
|
107
|
+
A single widget file covers both. Multiple `seller.setup.before` and `.after` widgets stack in registration order.
|
|
105
108
|
</Step>
|
|
106
109
|
</Steps>
|
|
107
110
|
|
|
108
111
|
<Note>
|
|
109
|
-
**`client` is your app's typed SDK.** `create-mercur-app` ships `apps/vendor/src/lib/client.ts
|
|
112
|
+
**`client` is your app's typed SDK.** `create-mercur-app` ships `apps/vendor/src/lib/client.ts`, a `createClient<Routes>()` instance. `client.vendor.sellers.$id.mutate(...)` is the typed `POST /vendor/sellers/:id`, so the request and response types match the backend route.
|
|
110
113
|
</Note>
|
|
111
114
|
|
|
112
|
-
##
|
|
115
|
+
## Carry the value through additional_data
|
|
113
116
|
|
|
114
|
-
You don't touch the seller route or its validator. Every vendor and admin seller route already wraps its body with `WithAdditionalData`, so an unknown `additional_data` object is accepted and forwarded into the workflow untouched
|
|
117
|
+
You don't touch the seller route or its validator. Every vendor and admin seller route already wraps its body with `WithAdditionalData`, so an unknown `additional_data` object is accepted and forwarded into the workflow untouched.
|
|
115
118
|
|
|
116
|
-
```ts packages/core/src/api/vendor/sellers/[id]/route.ts
|
|
119
|
+
```ts packages/core/src/api/vendor/sellers/[id]/route.ts
|
|
117
120
|
const { additional_data, ...update } = req.validatedBody
|
|
118
121
|
|
|
119
122
|
await updateSellersWorkflow(req.scope).run({
|
|
@@ -125,15 +128,15 @@ await updateSellersWorkflow(req.scope).run({
|
|
|
125
128
|
})
|
|
126
129
|
```
|
|
127
130
|
|
|
128
|
-
That is the whole
|
|
131
|
+
That is the whole wiring step. Your `{ tax_id }` payload arrives in the workflow as `additional_data` without a schema change.
|
|
129
132
|
|
|
130
|
-
##
|
|
133
|
+
## Persist it from a workflow hook
|
|
131
134
|
|
|
132
135
|
`updateSellersWorkflow` exposes a `sellersUpdated` hook that runs after the update with `{ sellers, additional_data }`. Subscribe to it in your Medusa app and persist the value.
|
|
133
136
|
|
|
134
137
|
<Steps>
|
|
135
138
|
<Step title="Declare a durable field">
|
|
136
|
-
Register a `Seller` custom field so the value gets a real, queryable column
|
|
139
|
+
Register a `Seller` custom field so the value gets a real, queryable column. No migration to hand-write.
|
|
137
140
|
|
|
138
141
|
```ts apps/api/medusa-config.ts
|
|
139
142
|
module.exports = defineConfig({
|
|
@@ -153,12 +156,12 @@ That is the whole "wiring" step: your `{ tax_id }` payload arrives in the workfl
|
|
|
153
156
|
})
|
|
154
157
|
```
|
|
155
158
|
|
|
156
|
-
```bash
|
|
159
|
+
```bash Terminal
|
|
157
160
|
bunx medusa db:migrate
|
|
158
161
|
```
|
|
159
162
|
</Step>
|
|
160
163
|
<Step title="Subscribe to the hook">
|
|
161
|
-
Drop a file under `src/workflows/` in your Medusa app. Medusa imports everything under `src/workflows` at boot, so registering the hook is just defining it. Read `additional_data
|
|
164
|
+
Drop a file under `src/workflows/` in your Medusa app. Medusa imports everything under `src/workflows` at boot, so registering the hook is just defining it. Read `additional_data` and upsert through the Custom Fields service.
|
|
162
165
|
|
|
163
166
|
```ts apps/api/src/workflows/hooks/seller-tax-id.ts
|
|
164
167
|
import { updateSellersWorkflow } from "@mercurjs/core/workflows"
|
|
@@ -182,11 +185,11 @@ That is the whole "wiring" step: your `{ tax_id }` payload arrives in the workfl
|
|
|
182
185
|
```
|
|
183
186
|
|
|
184
187
|
<Tip>
|
|
185
|
-
The hook fires for **every** seller update, not only your widget's
|
|
188
|
+
The hook fires for **every** seller update, not only your widget's. Always guard on the field being present (`typeof taxId !== "string"`) so unrelated edits, such as name, address, or status, pass through untouched.
|
|
186
189
|
</Tip>
|
|
187
190
|
</Step>
|
|
188
191
|
<Step title="Read it back">
|
|
189
|
-
The value is now linked to the seller and queryable through Medusa's remote query
|
|
192
|
+
The value is now linked to the seller and queryable through Medusa's remote query.
|
|
190
193
|
|
|
191
194
|
```ts
|
|
192
195
|
const { data: [seller] } = await query.graph({
|
|
@@ -217,27 +220,27 @@ seller.custom_fields.tax_id (durable, queryable)
|
|
|
217
220
|
|
|
218
221
|
## Verify
|
|
219
222
|
|
|
220
|
-
1. Open the vendor portal
|
|
221
|
-
2. Enter a value and save
|
|
223
|
+
1. Open the vendor portal. The Tax ID prompt renders on the dashboard home and on **Settings → Store**.
|
|
224
|
+
2. Enter a value and save. The mutation succeeds (`toast.success`) and hits `POST /vendor/sellers/:id`.
|
|
222
225
|
3. `query.graph({ entity: "seller", fields: ["custom_fields.tax_id"] })` returns the saved value.
|
|
223
|
-
4. Edit an unrelated field
|
|
224
|
-
5. Set `zone: "not.a.zone"` on the widget
|
|
225
|
-
6. Delete the widget file
|
|
226
|
+
4. Edit an unrelated field, such as store name. The seller update still works and the guard skips the upsert.
|
|
227
|
+
5. Set `zone: "not.a.zone"` on the widget. `bun run lint` (tsc) fails against `WidgetZoneId`.
|
|
228
|
+
6. Delete the widget file. The prompt disappears. The seller route and hook are unaffected.
|
|
226
229
|
|
|
227
230
|
## FAQ
|
|
228
231
|
|
|
229
232
|
<AccordionGroup>
|
|
230
233
|
<Accordion title="Why additional_data instead of adding a body field?">
|
|
231
|
-
The seller routes' validators are core-owned. `additional_data` is the sanctioned escape hatch
|
|
234
|
+
The seller routes' validators are core-owned. `additional_data` is the sanctioned escape hatch. Every vendor and admin route wraps its body with `WithAdditionalData`, so you carry extra context to the workflow hooks without patching the request schema or forking the route.
|
|
232
235
|
</Accordion>
|
|
233
236
|
<Accordion title="Which seller workflows expose hooks?">
|
|
234
|
-
`updateSellersWorkflow` exposes `sellersUpdated`, and `createSellerAccountWorkflow` (the `POST /vendor/sellers` onboarding submit) exposes `sellerAccountCreated
|
|
237
|
+
`updateSellersWorkflow` exposes `sellersUpdated`, and `createSellerAccountWorkflow` (the `POST /vendor/sellers` onboarding submit) exposes `sellerAccountCreated`. Both carry `{ additional_data }`. Use `sellerAccountCreated` to capture data at first registration and `sellersUpdated` for later edits. See the [Store workflows](/platform/store/reference/workflows).
|
|
235
238
|
</Accordion>
|
|
236
239
|
<Accordion title="Can I store it on the seller's metadata instead?">
|
|
237
|
-
Yes
|
|
240
|
+
Yes. For a quick, non-queryable value, resolve the seller module in the hook and write to `seller.metadata`. Reach for the [Custom Fields module](/rc/resources/customization/custom-fields) when you want a typed, queryable column, which is what most onboarding data such as tax IDs or compliance flags needs.
|
|
238
241
|
</Accordion>
|
|
239
242
|
<Accordion title="Does the hook run inside the request?">
|
|
240
|
-
Yes
|
|
243
|
+
Yes. Workflow hooks run as steps of the workflow the route invokes, with the same compensation and rollback semantics. If your hook throws, the seller update rolls back. Keep slow or best-effort work, such as external syncs, in a subscriber on the emitted `seller.updated` event instead.
|
|
241
244
|
</Accordion>
|
|
242
245
|
</AccordionGroup>
|
|
243
246
|
|
|
@@ -245,7 +248,7 @@ seller.custom_fields.tax_id (durable, queryable)
|
|
|
245
248
|
|
|
246
249
|
<CardGroup cols={2}>
|
|
247
250
|
<Card title="Extend a workflow" href="/rc/resources/customization/extend-a-workflow">
|
|
248
|
-
The full hook
|
|
251
|
+
The full hook and compensation model for Mercur workflows.
|
|
249
252
|
</Card>
|
|
250
253
|
<Card title="Custom Fields module" href="/rc/resources/customization/custom-fields">
|
|
251
254
|
Durable, queryable storage for the data your hook writes.
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
|
|
2
|
+
title: "How to Create Master Products and Offers"
|
|
3
|
+
sidebarTitle: "Master Products & Offers"
|
|
4
|
+
description: "Publish one master product, add two competing seller offers, and read per-offer prices from the Store API."
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
Mercur
|
|
7
|
+
Mercur runs a master catalog. One canonical product record holds many sellers listing against it. The product defines what the item is. Each seller's offer defines how they sell it: their SKU, price, stock, and shipping. This tutorial builds the classic buy-box scenario: two sellers, one product, two competing offers.
|
|
7
8
|
|
|
8
9
|
<Info>
|
|
9
|
-
|
|
10
|
+
No seller owns a product. There is no owner column. Creating a product adds a candidate to the shared catalog. The creator gets attribution, so their unpublished submissions appear in their own list, but no rights over the record after publication. What looks like ownership elsewhere is split into three things: selling eligibility, creator attribution, and the status lifecycle. See [Products](/rc/learn/products).
|
|
10
11
|
</Info>
|
|
11
12
|
|
|
12
13
|
## What you'll build
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
You end with a published master product carrying offers from two sellers at different prices. Both offers are visible side by side through the Store API, each with its own calculated price.
|
|
15
16
|
|
|
16
17
|
## Product vs offer
|
|
17
18
|
|
|
19
|
+
Three concerns live in three places. Keep them separate as you build.
|
|
20
|
+
|
|
18
21
|
| Concern | Lives on | Example |
|
|
19
22
|
|---------|----------|---------|
|
|
20
23
|
| What the item is | Master product | "Classic White T-Shirt", variants, attributes |
|
|
@@ -25,55 +28,57 @@ A published master product with offers from two sellers at different prices, vis
|
|
|
25
28
|
|
|
26
29
|
<Steps>
|
|
27
30
|
<Step title="Publish a master product">
|
|
28
|
-
As Seller A, create a product in the Vendor Portal
|
|
31
|
+
As Seller A, create a product in the Vendor Portal, such as "Classic White T-Shirt" with a size variant. It enters as `proposed`. As the operator, confirm it in the Admin Panel so it becomes `published`. The review flow is covered by the [Product Edit](/platform/product-edit/overview) module.
|
|
29
32
|
|
|
30
|
-
The published product now belongs to the shared catalog. Note what it does
|
|
33
|
+
The published product now belongs to the shared catalog. Note what it does not have: a seller price or seller stock.
|
|
31
34
|
</Step>
|
|
32
|
-
<Step title="Seller A
|
|
33
|
-
In Seller A's Vendor Portal, create an offer against the product's variant
|
|
35
|
+
<Step title="Create Seller A's offer">
|
|
36
|
+
In Seller A's Vendor Portal, create an offer against the product's variant. Give it their own SKU, a price of $25, stock of 100, and one of their shipping profiles.
|
|
34
37
|
|
|
35
38
|
<Warning>
|
|
36
|
-
Offer inventory
|
|
39
|
+
Offer inventory links to the offer, not the variant. Each seller manages stock for their own listing independently. A variant has no marketplace-wide stock figure, and its own `inventory_items` relation is empty for offer-based listings. Always read stock through the offer.
|
|
37
40
|
</Warning>
|
|
38
41
|
</Step>
|
|
39
|
-
<Step title="
|
|
40
|
-
As Seller B, find the same published product in the catalog and create a competing offer on the same variant
|
|
42
|
+
<Step title="List the same product as Seller B">
|
|
43
|
+
As Seller B, find the same published product in the catalog and create a competing offer on the same variant: a different SKU, $23, stock of 40. The `(seller_id, sku)` pair is unique per seller, so both sellers can use whatever SKU scheme they like.
|
|
41
44
|
|
|
42
45
|
Nothing about the master product changed. Two commercial listings now point at one catalog entry.
|
|
43
46
|
</Step>
|
|
44
47
|
<Step title="Read the buy box from the Store API">
|
|
45
|
-
The Store API exposes offers directly, each with its own calculated price:
|
|
48
|
+
The Store API exposes offers directly, each with its own calculated price. Fetch them by product id:
|
|
46
49
|
|
|
47
|
-
```bash
|
|
50
|
+
```bash Terminal
|
|
48
51
|
curl "http://localhost:9000/store/offers?product_id=prod_123" \
|
|
49
52
|
-H "x-publishable-api-key: <key>"
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
Offers share the variant's price set scoped by an offer rule
|
|
55
|
+
Offers share the variant's price set scoped by an offer rule. Each offer carries its own prices without duplicating the variant, and the storefront computes a `calculated_price` per offer. A buy-box storefront fetches the product once, then renders every seller's offer against it.
|
|
53
56
|
</Step>
|
|
54
57
|
<Step title="Check out against an offer">
|
|
55
|
-
Add Seller B's offer to a cart and place the order. The cart line item links to the
|
|
58
|
+
Add Seller B's offer to a cart and place the order. The cart line item links to the specific offer purchased, and that link is preserved onto the order line item. Fulfillment, [commission calculation](/rc/learn/commissions), and [payouts](/rc/learn/payouts) all resolve to Seller B, even though both sellers list the same variant.
|
|
56
59
|
</Step>
|
|
57
60
|
</Steps>
|
|
58
61
|
|
|
59
62
|
## Verify
|
|
60
63
|
|
|
64
|
+
Confirm the buy box behaves as expected.
|
|
65
|
+
|
|
61
66
|
1. Both offers appear in `GET /store/offers?product_id=...` with different `calculated_price` values.
|
|
62
|
-
2. Each seller's Vendor Portal shows only their own offer
|
|
63
|
-
3. After the checkout in step 5, the order lands with Seller B
|
|
64
|
-
4. Reducing Seller B's offer stock
|
|
67
|
+
2. Each seller's Vendor Portal shows only their own offer. The Admin Panel lists both with store, pricing, and inventory.
|
|
68
|
+
3. After the checkout in step 5, the order lands with Seller B. Seller A's offer and stock are untouched.
|
|
69
|
+
4. Reducing Seller B's offer stock does not affect Seller A's availability. Inventory is per offer.
|
|
65
70
|
|
|
66
71
|
## FAQ
|
|
67
72
|
|
|
68
73
|
<AccordionGroup>
|
|
69
74
|
<Accordion title="How do I restrict who may sell a product?">
|
|
70
|
-
The operator manages the `product_seller` allowlist
|
|
75
|
+
The operator manages the `product_seller` allowlist. A product with assignments is visible and sellable only for those sellers, while a product with no assignments is open to every seller. Eligibility limits selling. It does not limit who may propose edits to the shared record.
|
|
71
76
|
</Accordion>
|
|
72
77
|
<Accordion title="Can two sellers use the same SKU?">
|
|
73
|
-
Yes
|
|
78
|
+
Yes. SKU uniqueness is per seller (`seller_id` + `sku`). Seller A and Seller B can both use `TSHIRT-WHITE-M`. A single seller cannot list the same SKU twice.
|
|
74
79
|
</Accordion>
|
|
75
80
|
<Accordion title="Who fulfills, refunds, and gets paid when several sellers list the same variant?">
|
|
76
|
-
Always the seller whose
|
|
81
|
+
Always the seller whose offer was purchased. The offer link travels from cart line to order line, so fulfillment, returns, commission, and payout all resolve through it. The variant alone is never enough to identify the seller.
|
|
77
82
|
</Accordion>
|
|
78
83
|
</AccordionGroup>
|
|
79
84
|
|
|
@@ -84,6 +89,6 @@ A published master product with offers from two sellers at different prices, vis
|
|
|
84
89
|
The offer data model, relationships, and checkout links.
|
|
85
90
|
</Card>
|
|
86
91
|
<Card title="Order Groups" href="/rc/learn/order-groups">
|
|
87
|
-
What happens when a cart spans both sellers
|
|
92
|
+
What happens when a cart spans both sellers: the multi-vendor split.
|
|
88
93
|
</Card>
|
|
89
94
|
</CardGroup>
|
package/content/telemetry.mdx
CHANGED
|
@@ -39,7 +39,7 @@ When you run CLI commands (`create`, `init`, `add`, `registry:build`), the follo
|
|
|
39
39
|
### Using the CLI
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
mercurjs telemetry --disable
|
|
42
|
+
bunx @mercurjs/cli@latest telemetry --disable
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### Using an environment variable
|
|
@@ -53,7 +53,7 @@ This is useful for CI/CD environments or shared configurations.
|
|
|
53
53
|
### Check current status
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
mercurjs telemetry
|
|
56
|
+
bunx @mercurjs/cli@latest telemetry
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
## Where Data Goes
|
|
@@ -63,5 +63,5 @@ Telemetry events are sent to `https://telemetry.mercurjs.com`. The data is used
|
|
|
63
63
|
## Re-enabling Telemetry
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
mercurjs telemetry --enable
|
|
66
|
+
bunx @mercurjs/cli@latest telemetry --enable
|
|
67
67
|
```
|