@hartl-services/medusa-storefront 0.2.0 → 0.3.0

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.
@@ -7,8 +7,8 @@
7
7
  "title": "Storefront setup",
8
8
  "description": "Wires the storefront package into a Next shop: server and browser instances, the Server Action wrappers, texts, error reporting and the provider root for the [countryCode] layout.",
9
9
  "dependencies": [
10
- "@hartl-services/medusa-storefront@^0.2.0",
11
- "@hartl-services/medusa-contracts@^1.1.0",
10
+ "@hartl-services/medusa-storefront@^0.3.0",
11
+ "@hartl-services/medusa-contracts@^1.2.0",
12
12
  "@medusajs/framework@^2.19.0",
13
13
  "@medusajs/js-sdk@^2.19.0",
14
14
  "@medusajs/types@^2.19.0",
@@ -73,7 +73,7 @@
73
73
  "title": "Storefront form kit",
74
74
  "description": "The shop's TanStack form hook (useAppForm) with unstyled field components; the package's hooks hand their formOptions to it.",
75
75
  "dependencies": [
76
- "@hartl-services/medusa-storefront@^0.2.0",
76
+ "@hartl-services/medusa-storefront@^0.3.0",
77
77
  "@tanstack/react-form@^1.33.5",
78
78
  "input-otp",
79
79
  "lucide-react"
@@ -197,7 +197,7 @@
197
197
  "title": "Cart",
198
198
  "description": "Cart widget with popover, line items, totals, cart page, add-to-cart button, variant picker and product price.",
199
199
  "dependencies": [
200
- "@hartl-services/medusa-storefront@^0.2.0",
200
+ "@hartl-services/medusa-storefront@^0.3.0",
201
201
  "@medusajs/types@^2.19.0",
202
202
  "lucide-react"
203
203
  ],
@@ -306,8 +306,8 @@
306
306
  "title": "Customer account",
307
307
  "description": "Sign-in with password or e-mail code, password reset, account verification, address book with UID check, profile, orders, the account workspace layout and the document download route.",
308
308
  "dependencies": [
309
- "@hartl-services/medusa-storefront@^0.2.0",
310
- "@hartl-services/medusa-contracts@^1.1.0",
309
+ "@hartl-services/medusa-storefront@^0.3.0",
310
+ "@hartl-services/medusa-contracts@^1.2.0",
311
311
  "@medusajs/types@^2.19.0",
312
312
  "lucide-react"
313
313
  ],
@@ -516,7 +516,7 @@
516
516
  "title": "Checkout",
517
517
  "description": "Checkout page (address, login prompt, shipping and Stripe payment, coupon, UID status) and the order confirmation page.",
518
518
  "dependencies": [
519
- "@hartl-services/medusa-storefront@^0.2.0",
519
+ "@hartl-services/medusa-storefront@^0.3.0",
520
520
  "@medusajs/types@^2.19.0",
521
521
  "@stripe/react-stripe-js@^5.6.1",
522
522
  "@stripe/stripe-js@^8.11.0",
@@ -661,8 +661,8 @@
661
661
  "title": "Partner portal",
662
662
  "description": "Partner portal: gated registration with UID check, links, coupon codes, commissions with date filter, consignment reports, and its Route Handlers.",
663
663
  "dependencies": [
664
- "@hartl-services/medusa-storefront@^0.2.0",
665
- "@hartl-services/medusa-contracts@^1.1.0",
664
+ "@hartl-services/medusa-storefront@^0.3.0",
665
+ "@hartl-services/medusa-contracts@^1.2.0",
666
666
  "@medusajs/types@^2.19.0",
667
667
  "lucide-react",
668
668
  "react-day-picker"
@@ -4,8 +4,8 @@
4
4
  "title": "Storefront setup",
5
5
  "description": "Wires the storefront package into a Next shop: server and browser instances, the Server Action wrappers, texts, error reporting and the provider root for the [countryCode] layout.",
6
6
  "dependencies": [
7
- "@hartl-services/medusa-storefront@^0.2.0",
8
- "@hartl-services/medusa-contracts@^1.1.0",
7
+ "@hartl-services/medusa-storefront@^0.3.0",
8
+ "@hartl-services/medusa-contracts@^1.2.0",
9
9
  "@medusajs/framework@^2.19.0",
10
10
  "@medusajs/js-sdk@^2.19.0",
11
11
  "@medusajs/types@^2.19.0",
@@ -34,7 +34,7 @@
34
34
  "path": "registry/items/setup/lib/storefront/actions.ts",
35
35
  "target": "@lib/storefront/actions.ts",
36
36
  "type": "registry:lib",
37
- "content": "\"use server\"\n\n// One Server Action per storefront server function: Next only accepts \"use server\"\n// functions defined in the app. The browser side gets them through lib/storefront/client.ts.\n\nimport { storefront } from \"@/lib/storefront/server\"\n\nexport async function getActiveCart(...args: Parameters<typeof storefront.cart.getActiveCart>) {\n return await storefront.cart.getActiveCart(...args)\n}\n\nexport async function applyCustomerDefaultsToActiveCart(...args: Parameters<typeof storefront.cart.applyCustomerDefaultsToActiveCart>) {\n return await storefront.cart.applyCustomerDefaultsToActiveCart(...args)\n}\n\nexport async function syncCartId(...args: Parameters<typeof storefront.cart.syncCartId>) {\n return await storefront.cart.syncCartId(...args)\n}\n\nexport async function clearCartId(...args: Parameters<typeof storefront.cart.clearCartId>) {\n return await storefront.cart.clearCartId(...args)\n}\n\nexport async function discardActiveCart(...args: Parameters<typeof storefront.cart.discardActiveCart>) {\n return await storefront.cart.discardActiveCart(...args)\n}\n\nexport async function retrieveCustomer(...args: Parameters<typeof storefront.customer.retrieveCustomer>) {\n return await storefront.customer.retrieveCustomer(...args)\n}\n\nexport async function loginCustomer(...args: Parameters<typeof storefront.customer.loginCustomer>) {\n return await storefront.customer.loginCustomer(...args)\n}\n\nexport async function checkCustomerVerification(...args: Parameters<typeof storefront.customer.checkCustomerVerification>) {\n return await storefront.customer.checkCustomerVerification(...args)\n}\n\nexport async function registerCustomer(...args: Parameters<typeof storefront.customer.registerCustomer>) {\n return await storefront.customer.registerCustomer(...args)\n}\n\nexport async function registerCustomerWithProfile(...args: Parameters<typeof storefront.customer.registerCustomerWithProfile>) {\n return await storefront.customer.registerCustomerWithProfile(...args)\n}\n\nexport async function requestLoginCode(...args: Parameters<typeof storefront.customer.requestLoginCode>) {\n return await storefront.customer.requestLoginCode(...args)\n}\n\nexport async function loginWithCode(...args: Parameters<typeof storefront.customer.loginWithCode>) {\n return await storefront.customer.loginWithCode(...args)\n}\n\nexport async function requestCustomerPasswordReset(...args: Parameters<typeof storefront.customer.requestCustomerPasswordReset>) {\n return await storefront.customer.requestCustomerPasswordReset(...args)\n}\n\nexport async function resetCustomerPassword(...args: Parameters<typeof storefront.customer.resetCustomerPassword>) {\n return await storefront.customer.resetCustomerPassword(...args)\n}\n\nexport async function confirmCustomerEmail(...args: Parameters<typeof storefront.customer.confirmCustomerEmail>) {\n return await storefront.customer.confirmCustomerEmail(...args)\n}\n\nexport async function resendCustomerVerification(...args: Parameters<typeof storefront.customer.resendCustomerVerification>) {\n return await storefront.customer.resendCustomerVerification(...args)\n}\n\nexport async function fetchCustomerPasswordPolicy(...args: Parameters<typeof storefront.customer.fetchCustomerPasswordPolicy>) {\n return await storefront.customer.fetchCustomerPasswordPolicy(...args)\n}\n\nexport async function updateCustomer(...args: Parameters<typeof storefront.customer.updateCustomer>) {\n return await storefront.customer.updateCustomer(...args)\n}\n\nexport async function createCustomerAddress(...args: Parameters<typeof storefront.customer.createCustomerAddress>) {\n return await storefront.customer.createCustomerAddress(...args)\n}\n\nexport async function saveFirstCheckoutAddresses(...args: Parameters<typeof storefront.customer.saveFirstCheckoutAddresses>) {\n return await storefront.customer.saveFirstCheckoutAddresses(...args)\n}\n\nexport async function updateCustomerAddress(...args: Parameters<typeof storefront.customer.updateCustomerAddress>) {\n return await storefront.customer.updateCustomerAddress(...args)\n}\n\nexport async function deleteCustomerAddress(...args: Parameters<typeof storefront.customer.deleteCustomerAddress>) {\n return await storefront.customer.deleteCustomerAddress(...args)\n}\n\nexport async function logoutCustomer(...args: Parameters<typeof storefront.customer.logoutCustomer>) {\n return await storefront.customer.logoutCustomer(...args)\n}\n\nexport async function listShippingOptions(...args: Parameters<typeof storefront.checkout.listShippingOptions>) {\n return await storefront.checkout.listShippingOptions(...args)\n}\n\nexport async function listPaymentProviders(...args: Parameters<typeof storefront.checkout.listPaymentProviders>) {\n return await storefront.checkout.listPaymentProviders(...args)\n}\n\nexport async function listRegions(...args: Parameters<typeof storefront.region.listRegions>) {\n return await storefront.region.listRegions(...args)\n}\n\nexport async function fetchPluginFeatures(...args: Parameters<typeof storefront.pluginFeatures.fetchPluginFeatures>) {\n return await storefront.pluginFeatures.fetchPluginFeatures(...args)\n}\n\nexport async function checkCartTaxIdentification(...args: Parameters<typeof storefront.taxCompliance.checkCartTaxIdentification>) {\n return await storefront.taxCompliance.checkCartTaxIdentification(...args)\n}\n\nexport async function listCustomerTaxIdentifications(...args: Parameters<typeof storefront.taxCompliance.listCustomerTaxIdentifications>) {\n return await storefront.taxCompliance.listCustomerTaxIdentifications(...args)\n}\n\nexport async function verifyCustomerAddressTaxIdentification(...args: Parameters<typeof storefront.taxCompliance.verifyCustomerAddressTaxIdentification>) {\n return await storefront.taxCompliance.verifyCustomerAddressTaxIdentification(...args)\n}\n\nexport async function submitAffiliateApplication(...args: Parameters<typeof storefront.affiliate.submitAffiliateApplication>) {\n return await storefront.affiliate.submitAffiliateApplication(...args)\n}\n\nexport async function applyAffiliateOwnOrderPromotion(...args: Parameters<typeof storefront.affiliate.applyAffiliateOwnOrderPromotion>) {\n return await storefront.affiliate.applyAffiliateOwnOrderPromotion(...args)\n}\n\nexport async function createAffiliateSlug(...args: Parameters<typeof storefront.affiliate.createAffiliateSlug>) {\n return await storefront.affiliate.createAffiliateSlug(...args)\n}\n\nexport async function updateAffiliateSlug(...args: Parameters<typeof storefront.affiliate.updateAffiliateSlug>) {\n return await storefront.affiliate.updateAffiliateSlug(...args)\n}\n\nexport async function createAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.createAffiliateCouponCode>) {\n return await storefront.affiliate.createAffiliateCouponCode(...args)\n}\n\nexport async function rotateAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.rotateAffiliateCouponCode>) {\n return await storefront.affiliate.rotateAffiliateCouponCode(...args)\n}\n\nexport async function revokeAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.revokeAffiliateCouponCode>) {\n return await storefront.affiliate.revokeAffiliateCouponCode(...args)\n}\n\nexport async function createConsignmentReport(...args: Parameters<typeof storefront.affiliate.createConsignmentReport>) {\n return await storefront.affiliate.createConsignmentReport(...args)\n}\n\nexport async function listOrders(...args: Parameters<typeof storefront.orders.listOrders>) {\n return await storefront.orders.listOrders(...args)\n}\n\nexport async function getOrder(...args: Parameters<typeof storefront.orders.getOrder>) {\n return await storefront.orders.getOrder(...args)\n}\n\nexport async function listDocuments(...args: Parameters<typeof storefront.documents.listDocuments>) {\n return await storefront.documents.listDocuments(...args)\n}\n"
37
+ "content": "\"use server\"\n\n// One Server Action per storefront server function: Next only accepts \"use server\"\n// functions defined in the app. The browser side gets them through lib/storefront/client.ts.\n\nimport { storefront } from \"@/lib/storefront/server\"\n\nexport async function getActiveCart(...args: Parameters<typeof storefront.cart.getActiveCart>) {\n return await storefront.cart.getActiveCart(...args)\n}\n\nexport async function applyCustomerDefaultsToActiveCart(...args: Parameters<typeof storefront.cart.applyCustomerDefaultsToActiveCart>) {\n return await storefront.cart.applyCustomerDefaultsToActiveCart(...args)\n}\n\nexport async function syncCartId(...args: Parameters<typeof storefront.cart.syncCartId>) {\n return await storefront.cart.syncCartId(...args)\n}\n\nexport async function clearCartId(...args: Parameters<typeof storefront.cart.clearCartId>) {\n return await storefront.cart.clearCartId(...args)\n}\n\nexport async function discardActiveCart(...args: Parameters<typeof storefront.cart.discardActiveCart>) {\n return await storefront.cart.discardActiveCart(...args)\n}\n\nexport async function retrieveCustomer(...args: Parameters<typeof storefront.customer.retrieveCustomer>) {\n return await storefront.customer.retrieveCustomer(...args)\n}\n\nexport async function loginCustomer(...args: Parameters<typeof storefront.customer.loginCustomer>) {\n return await storefront.customer.loginCustomer(...args)\n}\n\nexport async function checkCustomerVerification(...args: Parameters<typeof storefront.customer.checkCustomerVerification>) {\n return await storefront.customer.checkCustomerVerification(...args)\n}\n\nexport async function registerCustomer(...args: Parameters<typeof storefront.customer.registerCustomer>) {\n return await storefront.customer.registerCustomer(...args)\n}\n\nexport async function registerCustomerWithProfile(...args: Parameters<typeof storefront.customer.registerCustomerWithProfile>) {\n return await storefront.customer.registerCustomerWithProfile(...args)\n}\n\nexport async function registerPartnerWithProfile(...args: Parameters<typeof storefront.customer.registerPartnerWithProfile>) {\n return await storefront.customer.registerPartnerWithProfile(...args)\n}\n\nexport async function requestLoginCode(...args: Parameters<typeof storefront.customer.requestLoginCode>) {\n return await storefront.customer.requestLoginCode(...args)\n}\n\nexport async function loginWithCode(...args: Parameters<typeof storefront.customer.loginWithCode>) {\n return await storefront.customer.loginWithCode(...args)\n}\n\nexport async function requestCustomerPasswordReset(...args: Parameters<typeof storefront.customer.requestCustomerPasswordReset>) {\n return await storefront.customer.requestCustomerPasswordReset(...args)\n}\n\nexport async function resetCustomerPassword(...args: Parameters<typeof storefront.customer.resetCustomerPassword>) {\n return await storefront.customer.resetCustomerPassword(...args)\n}\n\nexport async function confirmCustomerEmail(...args: Parameters<typeof storefront.customer.confirmCustomerEmail>) {\n return await storefront.customer.confirmCustomerEmail(...args)\n}\n\nexport async function resendCustomerVerification(...args: Parameters<typeof storefront.customer.resendCustomerVerification>) {\n return await storefront.customer.resendCustomerVerification(...args)\n}\n\nexport async function fetchCustomerPasswordPolicy(...args: Parameters<typeof storefront.customer.fetchCustomerPasswordPolicy>) {\n return await storefront.customer.fetchCustomerPasswordPolicy(...args)\n}\n\nexport async function updateCustomer(...args: Parameters<typeof storefront.customer.updateCustomer>) {\n return await storefront.customer.updateCustomer(...args)\n}\n\nexport async function createCustomerAddress(...args: Parameters<typeof storefront.customer.createCustomerAddress>) {\n return await storefront.customer.createCustomerAddress(...args)\n}\n\nexport async function saveFirstCheckoutAddresses(...args: Parameters<typeof storefront.customer.saveFirstCheckoutAddresses>) {\n return await storefront.customer.saveFirstCheckoutAddresses(...args)\n}\n\nexport async function updateCustomerAddress(...args: Parameters<typeof storefront.customer.updateCustomerAddress>) {\n return await storefront.customer.updateCustomerAddress(...args)\n}\n\nexport async function deleteCustomerAddress(...args: Parameters<typeof storefront.customer.deleteCustomerAddress>) {\n return await storefront.customer.deleteCustomerAddress(...args)\n}\n\nexport async function logoutCustomer(...args: Parameters<typeof storefront.customer.logoutCustomer>) {\n return await storefront.customer.logoutCustomer(...args)\n}\n\nexport async function listShippingOptions(...args: Parameters<typeof storefront.checkout.listShippingOptions>) {\n return await storefront.checkout.listShippingOptions(...args)\n}\n\nexport async function listPaymentProviders(...args: Parameters<typeof storefront.checkout.listPaymentProviders>) {\n return await storefront.checkout.listPaymentProviders(...args)\n}\n\nexport async function listRegions(...args: Parameters<typeof storefront.region.listRegions>) {\n return await storefront.region.listRegions(...args)\n}\n\nexport async function fetchPluginFeatures(...args: Parameters<typeof storefront.pluginFeatures.fetchPluginFeatures>) {\n return await storefront.pluginFeatures.fetchPluginFeatures(...args)\n}\n\nexport async function checkCartTaxIdentification(...args: Parameters<typeof storefront.taxCompliance.checkCartTaxIdentification>) {\n return await storefront.taxCompliance.checkCartTaxIdentification(...args)\n}\n\nexport async function listCustomerTaxIdentifications(...args: Parameters<typeof storefront.taxCompliance.listCustomerTaxIdentifications>) {\n return await storefront.taxCompliance.listCustomerTaxIdentifications(...args)\n}\n\nexport async function verifyCustomerAddressTaxIdentification(...args: Parameters<typeof storefront.taxCompliance.verifyCustomerAddressTaxIdentification>) {\n return await storefront.taxCompliance.verifyCustomerAddressTaxIdentification(...args)\n}\n\nexport async function submitAffiliateApplication(...args: Parameters<typeof storefront.affiliate.submitAffiliateApplication>) {\n return await storefront.affiliate.submitAffiliateApplication(...args)\n}\n\nexport async function applyAffiliateOwnOrderPromotion(...args: Parameters<typeof storefront.affiliate.applyAffiliateOwnOrderPromotion>) {\n return await storefront.affiliate.applyAffiliateOwnOrderPromotion(...args)\n}\n\nexport async function createAffiliateSlug(...args: Parameters<typeof storefront.affiliate.createAffiliateSlug>) {\n return await storefront.affiliate.createAffiliateSlug(...args)\n}\n\nexport async function updateAffiliateSlug(...args: Parameters<typeof storefront.affiliate.updateAffiliateSlug>) {\n return await storefront.affiliate.updateAffiliateSlug(...args)\n}\n\nexport async function createAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.createAffiliateCouponCode>) {\n return await storefront.affiliate.createAffiliateCouponCode(...args)\n}\n\nexport async function rotateAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.rotateAffiliateCouponCode>) {\n return await storefront.affiliate.rotateAffiliateCouponCode(...args)\n}\n\nexport async function revokeAffiliateCouponCode(...args: Parameters<typeof storefront.affiliate.revokeAffiliateCouponCode>) {\n return await storefront.affiliate.revokeAffiliateCouponCode(...args)\n}\n\nexport async function createConsignmentReport(...args: Parameters<typeof storefront.affiliate.createConsignmentReport>) {\n return await storefront.affiliate.createConsignmentReport(...args)\n}\n\nexport async function listOrders(...args: Parameters<typeof storefront.orders.listOrders>) {\n return await storefront.orders.listOrders(...args)\n}\n\nexport async function getOrder(...args: Parameters<typeof storefront.orders.getOrder>) {\n return await storefront.orders.getOrder(...args)\n}\n\nexport async function listDocuments(...args: Parameters<typeof storefront.documents.listDocuments>) {\n return await storefront.documents.listDocuments(...args)\n}\n"
38
38
  },
39
39
  {
40
40
  "path": "registry/items/setup/lib/storefront/client.ts",
@@ -1,4 +1,4 @@
1
- import type { ApplyOwnOrderPromotionResponse, CreatePartnerPortalSlugRequest, CreateStoreAffiliateCouponCodeRequest, RotateStoreAffiliateCouponCodeRequest, SubmitAffiliateApplicationRequest, SubmitConsignmentReportRequest, UpdatePartnerPortalSlugRequest } from "@hartl-services/medusa-contracts/types/affiliate-store";
1
+ import type { ApplyOwnOrderPromotionResponse, CreatePartnerPortalSlugRequest, CreateStoreAffiliateCouponCodeRequest, RotateStoreAffiliateCouponCodeRequest, StoreAffiliatePortalContextResponse, SubmitAffiliateApplicationRequest, SubmitConsignmentReportRequest, UpdatePartnerPortalSlugRequest } from "@hartl-services/medusa-contracts/types/affiliate-store";
2
2
  import type { MedusaActionResult } from "../core/action-result.js";
3
3
  import type { ServerContext } from "./context.js";
4
4
  import type { ServerPluginFeatures } from "./plugin-features.js";
@@ -12,6 +12,9 @@ export interface AffiliateCouponRotationInput {
12
12
  command: RotateStoreAffiliateCouponCodeRequest;
13
13
  }
14
14
  export declare function createAffiliate(context: ServerContext, pluginFeatures: ServerPluginFeatures, runMedusaAction: RunMedusaAction): {
15
+ loadPartnerPortalState: () => Promise<StoreAffiliatePortalContextResponse["portal_state"] | null>;
16
+ /** Whether the logged-in customer is an approved, active partner (fail-closed). */
17
+ isActivePartner(): Promise<boolean>;
15
18
  submitAffiliateApplication(data: SubmitAffiliateApplicationRequest): Promise<MedusaActionResult<{
16
19
  application: {
17
20
  id: string;
@@ -1,3 +1,4 @@
1
+ import { cache } from "react";
1
2
  import { affiliateStorePaths } from "@hartl-services/medusa-contracts/paths/affiliate";
2
3
  import { isPluginFeatureEnabled } from "../core/plugin-features.js";
3
4
  import { createMedusaErrorResponse } from "./route-response.js";
@@ -19,7 +20,35 @@ export function createAffiliate(context, pluginFeatures, runMedusaAction) {
19
20
  return medusaErrorResponse(error);
20
21
  }
21
22
  }
23
+ /**
24
+ * The logged-in customer's partner state for server rendering (e.g. a
25
+ * therapist view): null when logged out, while the partner portal is off,
26
+ * or when the backend cannot answer - every partner view then stays hidden.
27
+ * Deduplicated per request via React cache().
28
+ */
29
+ const loadPartnerPortalState = cache(async () => {
30
+ if (!(await context.session.getMedusaAuthToken())) {
31
+ return null;
32
+ }
33
+ if (!isPluginFeatureEnabled(await pluginFeatures.loadPluginFeatures(), "affiliate", "partner_portal")) {
34
+ return null;
35
+ }
36
+ try {
37
+ const sdk = await customerClient();
38
+ const response = await sdk.client.fetch(affiliateStorePaths.get.me, { method: "GET" });
39
+ return response.portal_state;
40
+ }
41
+ catch (error) {
42
+ context.reportError(error, { area: "affiliate", context: { step: "portal_state" } });
43
+ return null;
44
+ }
45
+ });
22
46
  return {
47
+ loadPartnerPortalState,
48
+ /** Whether the logged-in customer is an approved, active partner (fail-closed). */
49
+ async isActivePartner() {
50
+ return (await loadPartnerPortalState()) === "active";
51
+ },
23
52
  async submitAffiliateApplication(data) {
24
53
  return runMedusaAction(async () => {
25
54
  const sdk = await customerClient();
@@ -9,8 +9,13 @@ export interface CommerceProductListInput {
9
9
  /** Medusa's product search (title, description, handle, ...). */
10
10
  q?: string;
11
11
  }
12
- /** Medusa's half of a catalog: products priced for a country, categories and collections. */
13
- export declare function createCatalog(context: ServerContext, region: ServerRegion): {
12
+ /**
13
+ * Medusa's half of a catalog: products priced for a country, categories and
14
+ * collections. Partner-only products and categories (see
15
+ * `isPartnerOnlyProduct`) are left out unless `isActivePartner` says the
16
+ * visitor is an active partner; the backend refuses them at checkout anyway.
17
+ */
18
+ export declare function createCatalog(context: ServerContext, region: ServerRegion, isActivePartner?: () => Promise<boolean>): {
14
19
  listCommerceProducts({ categoryId, collectionId, countryCode, handles, q }: CommerceProductListInput): Promise<HttpTypes.StoreProduct[] | null>;
15
20
  commerceProductByHandle({ countryCode, handle }: {
16
21
  countryCode: string;
@@ -19,7 +24,8 @@ export declare function createCatalog(context: ServerContext, region: ServerRegi
19
24
  /**
20
25
  * The top-level categories with all descendants (e.g. "Anwendungsbereiche"
21
26
  * and "Inhaltsstoffe" with their entries) - the filter trees of a product
22
- * list; filter with `filterProductsByCategories` from /core.
27
+ * list; filter with `filterProductsByCategories` from /core. Partner-only
28
+ * categories only for an active partner.
23
29
  */
24
30
  listCategoryTrees(): Promise<HttpTypes.StoreProductCategory[]>;
25
31
  categoryByPath(categoryPath: string[]): Promise<HttpTypes.StoreProductCategory | null>;
@@ -1,7 +1,14 @@
1
+ import { cache } from "react";
2
+ import { collectPartnerOnlyCategoryIds, isPartnerOnlyProduct, withoutPartnerOnlyCategories } from "../core/catalog/partner-only.js";
1
3
  import { CATEGORY_FIELDS, COLLECTION_FIELDS, PRODUCT_FIELDS } from "../core/fields.js";
2
4
  const catalogFetchLimit = 100;
3
- /** Medusa's half of a catalog: products priced for a country, categories and collections. */
4
- export function createCatalog(context, region) {
5
+ /**
6
+ * Medusa's half of a catalog: products priced for a country, categories and
7
+ * collections. Partner-only products and categories (see
8
+ * `isPartnerOnlyProduct`) are left out unless `isActivePartner` says the
9
+ * visitor is an active partner; the backend refuses them at checkout anyway.
10
+ */
11
+ export function createCatalog(context, region, isActivePartner = async () => false) {
5
12
  async function getPricingContext(countryCode) {
6
13
  const countryRegion = await region.getRegionForCountry(countryCode);
7
14
  if (!countryRegion) {
@@ -13,6 +20,29 @@ export function createCatalog(context, region) {
13
20
  region_id: countryRegion.id,
14
21
  };
15
22
  }
23
+ // Every top-level category with all descendants, once per request.
24
+ const loadCategoryTrees = cache(async () => {
25
+ const sdk = context.createMedusaClient();
26
+ const { product_categories: productCategories } = await sdk.store.category.list({
27
+ fields: "id,name,handle,description,metadata,rank,*category_children",
28
+ include_descendants_tree: true,
29
+ limit: catalogFetchLimit,
30
+ parent_category_id: "null",
31
+ });
32
+ return productCategories;
33
+ });
34
+ /**
35
+ * Leaves out partner-only products for everyone but an active partner. The
36
+ * partner check (a backend request) only runs when a partner-only product
37
+ * is among them, so a shop without any pays nothing for it; the category
38
+ * trees are only read when a product has categories.
39
+ */
40
+ async function visibleProducts(products) {
41
+ const hasCategories = products.some((product) => (product.categories?.length ?? 0) > 0);
42
+ const partnerOnlyCategoryIds = hasCategories ? collectPartnerOnlyCategoryIds(await loadCategoryTrees()) : new Set();
43
+ const visible = products.filter((product) => !isPartnerOnlyProduct(product, partnerOnlyCategoryIds));
44
+ return visible.length === products.length || !(await isActivePartner()) ? visible : products;
45
+ }
16
46
  return {
17
47
  async listCommerceProducts({ categoryId, collectionId, countryCode, handles, q }) {
18
48
  const pricingContext = await getPricingContext(countryCode);
@@ -29,7 +59,7 @@ export function createCatalog(context, region) {
29
59
  fields: PRODUCT_FIELDS,
30
60
  limit: catalogFetchLimit,
31
61
  });
32
- return products;
62
+ return await visibleProducts(products);
33
63
  },
34
64
  async commerceProductByHandle({ countryCode, handle }) {
35
65
  const pricingContext = await getPricingContext(countryCode);
@@ -43,22 +73,20 @@ export function createCatalog(context, region) {
43
73
  handle,
44
74
  limit: 1,
45
75
  });
46
- return products[0] ?? null;
76
+ return (await visibleProducts(products))[0] ?? null;
47
77
  },
48
78
  /**
49
79
  * The top-level categories with all descendants (e.g. "Anwendungsbereiche"
50
80
  * and "Inhaltsstoffe" with their entries) - the filter trees of a product
51
- * list; filter with `filterProductsByCategories` from /core.
81
+ * list; filter with `filterProductsByCategories` from /core. Partner-only
82
+ * categories only for an active partner.
52
83
  */
53
84
  async listCategoryTrees() {
54
- const sdk = context.createMedusaClient();
55
- const { product_categories: productCategories } = await sdk.store.category.list({
56
- fields: "id,name,handle,description,metadata,rank,*category_children",
57
- include_descendants_tree: true,
58
- limit: catalogFetchLimit,
59
- parent_category_id: "null",
60
- });
61
- return productCategories;
85
+ const trees = await loadCategoryTrees();
86
+ if (collectPartnerOnlyCategoryIds(trees).size === 0) {
87
+ return trees;
88
+ }
89
+ return (await isActivePartner()) ? trees : withoutPartnerOnlyCategories(trees);
62
90
  },
63
91
  async categoryByPath(categoryPath) {
64
92
  const sdk = context.createMedusaClient();
@@ -67,7 +95,11 @@ export function createCatalog(context, region) {
67
95
  handle: categoryPath.join("/"),
68
96
  limit: 1,
69
97
  });
70
- return productCategories[0] ?? null;
98
+ const category = productCategories[0] ?? null;
99
+ if (!category || !collectPartnerOnlyCategoryIds(await loadCategoryTrees()).has(category.id)) {
100
+ return category;
101
+ }
102
+ return (await isActivePartner()) ? category : null;
71
103
  },
72
104
  async collectionByHandle(handle) {
73
105
  const sdk = context.createMedusaClient();
@@ -1,6 +1,7 @@
1
1
  import type { LoginWithCodeRequest, RequestLoginCodeRequest } from "@hartl-services/medusa-contracts/types/customer-auth-store";
2
- import type { CheckoutAddressValues, CustomerAddressValues, CustomerAuthValues, CustomerProfileValues, CustomerRegistrationProfileValues, VerificationResendValues } from "../core/form-values.js";
2
+ import type { CheckoutAddressValues, CustomerAddressValues, CustomerAuthValues, CustomerProfileValues, CustomerRegistrationProfileValues, PartnerRegistrationProfileValues, VerificationResendValues } from "../core/form-values.js";
3
3
  import type { ServerContext } from "./context.js";
4
+ import type { ServerPluginFeatures } from "./plugin-features.js";
4
5
  import type { RunMedusaAction } from "./run-medusa-action.js";
5
6
  export interface UpdateCustomerAddressInput {
6
7
  addressId: string;
@@ -10,7 +11,7 @@ export interface UpdateCustomerAddressInput {
10
11
  metadata?: Record<string, unknown>;
11
12
  };
12
13
  }
13
- export declare function createCustomer(context: ServerContext, runMedusaAction: RunMedusaAction): {
14
+ export declare function createCustomer(context: ServerContext, runMedusaAction: RunMedusaAction, pluginFeatures: ServerPluginFeatures): {
14
15
  retrieveCustomer(): Promise<import("@medusajs/types").StoreCustomerResponse | null>;
15
16
  loginCustomer(data: CustomerAuthValues): Promise<import("../core/action-result.js").MedusaActionResult<{
16
17
  state: "success";
@@ -40,12 +41,32 @@ export declare function createCustomer(context: ServerContext, runMedusaAction:
40
41
  */
41
42
  registerCustomerWithProfile(data: CustomerRegistrationProfileValues): Promise<import("../core/action-result.js").MedusaActionResult<{
42
43
  state: "verification_required";
44
+ addressId?: undefined;
43
45
  addressSaved?: undefined;
44
46
  sessionToken?: undefined;
45
47
  } | {
46
48
  addressSaved: boolean;
49
+ sessionToken: string;
47
50
  state: "success";
51
+ }>>;
52
+ /**
53
+ * Partner (e.g. therapist) registration: the account with its company
54
+ * address as default address, then the partner application from that
55
+ * address. Like the plain registration it counts as registered even if a
56
+ * later step fails (`addressSaved` / `applicationSubmitted` false). While
57
+ * the e-mail is unconfirmed, address and application wait until the
58
+ * first login. Refused up front while the partner portal is off.
59
+ */
60
+ registerPartnerWithProfile(data: PartnerRegistrationProfileValues): Promise<import("../core/action-result.js").MedusaActionResult<{
61
+ state: "verification_required";
62
+ addressId?: undefined;
63
+ addressSaved?: undefined;
64
+ sessionToken?: undefined;
65
+ } | {
66
+ addressSaved: boolean;
67
+ applicationSubmitted: boolean;
48
68
  sessionToken: string;
69
+ state: "success";
49
70
  }>>;
50
71
  requestLoginCode(data: RequestLoginCodeRequest): Promise<import("../core/action-result.js").MedusaActionResult<void>>;
51
72
  loginWithCode(data: LoginWithCodeRequest): Promise<import("../core/action-result.js").MedusaActionResult<{
@@ -1,12 +1,15 @@
1
1
  import { customerAuthStorePaths } from "@hartl-services/medusa-contracts/paths/customer-auth";
2
2
  import { EMAIL_OTP_AUTH_PROVIDER, LoginWithCodeSchema, RequestLoginCodeSchema, normalizeLoginEmail } from "@hartl-services/medusa-contracts/schemas/customer-auth";
3
3
  import { customerVerificationStorePaths } from "@hartl-services/medusa-contracts/paths/customer-verification";
4
+ import { affiliateStorePaths } from "@hartl-services/medusa-contracts/paths/affiliate";
5
+ import { TAX_COMPLIANCE_FEATURES, TAX_COMPLIANCE_PLUGIN_KEY, taxCompliancePaths } from "@hartl-services/medusa-contracts/paths/tax-compliance";
4
6
  import { vatNumberMetadataPatch } from "../core/addresses.js";
5
7
  import { completeCustomerSignIn as completeCustomerSignInWith, loginWithEmailpass } from "../core/auth/customer-sign-in.js";
6
8
  import { toCustomerAddressesFromCheckout } from "../core/checkout/checkout-address-draft.js";
7
9
  import { StorefrontError } from "../core/errors.js";
8
10
  import { CART_OWNER_FIELDS, CUSTOMER_FIELDS } from "../core/fields.js";
9
- import { createCheckoutAddressSchema, createVerificationResendSchema, customerAddressSchema, customerAuthSchema, customerProfileSchema, customerRegistrationProfileSchema, registrationAddressSchema } from "../core/form-values.js";
11
+ import { createCheckoutAddressSchema, createVerificationResendSchema, customerAddressSchema, customerAuthSchema, customerProfileSchema, customerRegistrationProfileSchema, partnerRegistrationProfileSchema, registrationAddressSchema } from "../core/form-values.js";
12
+ import { isPluginFeatureEnabled } from "../core/plugin-features.js";
10
13
  function cartCustomerHasAccount(cart) {
11
14
  const customer = Reflect.get(cart, "customer");
12
15
  return typeof customer === "object" && customer !== null && Reflect.get(customer, "has_account") === true;
@@ -20,10 +23,23 @@ function isVerificationRequired(result) {
20
23
  * no token to add one, so it waits here until the first login.
21
24
  */
22
25
  const PENDING_REGISTRATION_ADDRESS_KEY = "pending_registration_address";
26
+ /**
27
+ * Metadata key of a partner application that waits for its company address
28
+ * (the registration address): submitted right after the address is stored.
29
+ */
30
+ const PENDING_PARTNER_APPLICATION_KEY = "pending_partner_application";
31
+ function toPendingPartnerApplication(value) {
32
+ return typeof value === "object" && value !== null ? { confirmed_without_vat_number: Reflect.get(value, "confirmed_without_vat_number") === true } : null;
33
+ }
34
+ /** The registration address the customer create took last (Medusa answers with the whole customer). */
35
+ function findDefaultAddressId(customer) {
36
+ const addresses = customer.addresses ?? [];
37
+ return (addresses.find(({ is_default_billing }) => is_default_billing) ?? addresses[0])?.id ?? null;
38
+ }
23
39
  function getAuthenticationToken(result) {
24
40
  return typeof result === "string" ? result : null;
25
41
  }
26
- export function createCustomer(context, runMedusaAction) {
42
+ export function createCustomer(context, runMedusaAction, pluginFeatures) {
27
43
  const { createAuthenticatedMedusaClient, createMedusaClient, session } = context;
28
44
  async function requestCustomerVerification(email, token) {
29
45
  const sdk = createAuthenticatedMedusaClient(token);
@@ -78,40 +94,80 @@ export function createCustomer(context, runMedusaAction) {
78
94
  }
79
95
  }
80
96
  /**
81
- * Stores the registration address as the customer's default address. True
82
- * when stored (or nothing to store); never throws - a failing address must
83
- * not turn a registration or login into a failure.
97
+ * Stores the registration address as the customer's default address.
98
+ * `saved` is true when stored (or nothing to store); never throws - a
99
+ * failing address must not turn a registration or login into a failure.
84
100
  */
85
101
  async function storeRegistrationAddress(token, profile, address) {
86
102
  const parsed = registrationAddressSchema.safeParse(address);
87
103
  if (!parsed.success) {
88
- return true;
104
+ return { addressId: null, saved: true };
89
105
  }
90
106
  try {
91
107
  const sdk = createAuthenticatedMedusaClient(token);
92
- await sdk.store.customer.createAddress({
93
- ...parsed.data,
108
+ const { vat_number: vatNumber, ...addressValues } = parsed.data;
109
+ const { customer } = await sdk.store.customer.createAddress({
110
+ ...addressValues,
94
111
  first_name: profile.first_name ?? undefined,
95
112
  is_default_billing: true,
96
113
  is_default_shipping: true,
97
114
  last_name: profile.last_name ?? undefined,
98
115
  phone: profile.phone || undefined,
99
- });
116
+ ...(vatNumber ? { metadata: vatNumberMetadataPatch(vatNumber) } : {}),
117
+ }, { fields: "*addresses" });
100
118
  await sdk.store.customer.update({ metadata: { [PENDING_REGISTRATION_ADDRESS_KEY]: null } });
101
- return true;
119
+ return { addressId: findDefaultAddressId(customer), saved: true };
102
120
  }
103
121
  catch (error) {
104
122
  context.reportError(error, { area: "customer-auth", context: { step: "registration_address" } });
123
+ return { addressId: null, saved: false };
124
+ }
125
+ }
126
+ /**
127
+ * Submits a registration's partner application with its company address:
128
+ * a UID is checked first (the application takes it only once checked; an
129
+ * unreachable check counts too), and the pending marker is cleared either
130
+ * way. True when submitted; never throws - the account stays registered.
131
+ */
132
+ async function submitPartnerApplication(token, addressId, hasVatNumber, application) {
133
+ const sdk = createAuthenticatedMedusaClient(token);
134
+ try {
135
+ if (hasVatNumber && isPluginFeatureEnabled(await pluginFeatures.loadPluginFeatures(), TAX_COMPLIANCE_PLUGIN_KEY, TAX_COMPLIANCE_FEATURES.vatValidation)) {
136
+ await sdk.client.fetch(taxCompliancePaths.store.customers.addressTaxIdentification(addressId), { method: "POST" });
137
+ }
138
+ await sdk.client.fetch(affiliateStorePaths.post.register, {
139
+ body: { confirmed_without_vat_number: application.confirmed_without_vat_number, customer_address_id: addressId },
140
+ method: "POST",
141
+ });
142
+ return true;
143
+ }
144
+ catch (error) {
145
+ context.reportError(error, { area: "affiliate", context: { step: "registration_application" } });
105
146
  return false;
106
147
  }
148
+ finally {
149
+ try {
150
+ await sdk.store.customer.update({ metadata: { [PENDING_PARTNER_APPLICATION_KEY]: null } });
151
+ }
152
+ catch (error) {
153
+ context.reportError(error, { area: "affiliate", context: { step: "registration_application_cleanup" } });
154
+ }
155
+ }
107
156
  }
108
- /** After a login: adds a registration address that waited for the e-mail confirmation. */
157
+ /**
158
+ * After a login: adds a registration address that waited for the e-mail
159
+ * confirmation, then the partner application that waited for it.
160
+ */
109
161
  async function applyPendingRegistrationAddress(token) {
110
162
  try {
111
163
  const { customer } = await createAuthenticatedMedusaClient(token).store.customer.retrieve({ fields: "first_name,last_name,phone,metadata,*addresses" });
112
164
  const pending = customer.metadata?.[PENDING_REGISTRATION_ADDRESS_KEY];
113
165
  if (pending && (customer.addresses?.length ?? 0) === 0) {
114
- await storeRegistrationAddress(token, customer, pending);
166
+ const { addressId } = await storeRegistrationAddress(token, customer, pending);
167
+ const application = toPendingPartnerApplication(customer.metadata?.[PENDING_PARTNER_APPLICATION_KEY]);
168
+ if (addressId && application) {
169
+ await submitPartnerApplication(token, addressId, Boolean(registrationAddressSchema.safeParse(pending).data?.vat_number), application);
170
+ }
115
171
  }
116
172
  }
117
173
  catch (error) {
@@ -127,6 +183,34 @@ export function createCustomer(context, runMedusaAction) {
127
183
  await applyPendingRegistrationAddress(result.sessionToken);
128
184
  return result;
129
185
  }
186
+ async function registerWithProfile(parsed, metadata = {}) {
187
+ const credentials = { email: parsed.email, password: parsed.password };
188
+ const registrationSdk = createMedusaClient();
189
+ const registrationToken = await registrationSdk.auth.register("customer", "emailpass", credentials);
190
+ const customerSdk = createAuthenticatedMedusaClient(registrationToken);
191
+ const pendingMetadata = { ...(parsed.address ? { [PENDING_REGISTRATION_ADDRESS_KEY]: parsed.address } : {}), ...metadata };
192
+ const { customer } = await customerSdk.store.customer.create({
193
+ email: parsed.email,
194
+ first_name: parsed.first_name,
195
+ last_name: parsed.last_name,
196
+ ...(parsed.phone ? { phone: parsed.phone } : {}),
197
+ ...(Object.keys(pendingMetadata).length > 0 ? { metadata: pendingMetadata } : {}),
198
+ });
199
+ const loginSdk = createMedusaClient();
200
+ const result = await loginSdk.auth.login("customer", "emailpass", credentials);
201
+ if (isVerificationRequired(result)) {
202
+ await requestCustomerVerification(parsed.email, result.token);
203
+ return { state: "verification_required" };
204
+ }
205
+ const token = getAuthenticationToken(result);
206
+ if (!token) {
207
+ throw new StorefrontError("auth.registration_unsupported_step");
208
+ }
209
+ await transferActiveCartToCustomer(createAuthenticatedMedusaClient(token), { id: customer.id, email: parsed.email });
210
+ await session.setMedusaAuthToken(token);
211
+ const { addressId, saved } = parsed.address ? await storeRegistrationAddress(token, parsed, parsed.address) : { addressId: null, saved: true };
212
+ return { addressId, addressSaved: saved, state: "success", sessionToken: token };
213
+ }
130
214
  async function signInCustomer(data, { requestVerificationMail }) {
131
215
  const parsed = customerAuthSchema.parse(data);
132
216
  return runMedusaAction(async () => {
@@ -202,32 +286,32 @@ export function createCustomer(context, runMedusaAction) {
202
286
  */
203
287
  async registerCustomerWithProfile(data) {
204
288
  const parsed = customerRegistrationProfileSchema.parse(data);
205
- const credentials = { email: parsed.email, password: parsed.password };
206
289
  return runMedusaAction(async () => {
207
- const registrationSdk = createMedusaClient();
208
- const registrationToken = await registrationSdk.auth.register("customer", "emailpass", credentials);
209
- const customerSdk = createAuthenticatedMedusaClient(registrationToken);
210
- const { customer } = await customerSdk.store.customer.create({
211
- email: parsed.email,
212
- first_name: parsed.first_name,
213
- last_name: parsed.last_name,
214
- ...(parsed.phone ? { phone: parsed.phone } : {}),
215
- ...(parsed.address ? { metadata: { [PENDING_REGISTRATION_ADDRESS_KEY]: parsed.address } } : {}),
216
- });
217
- const loginSdk = createMedusaClient();
218
- const result = await loginSdk.auth.login("customer", "emailpass", credentials);
219
- if (isVerificationRequired(result)) {
220
- await requestCustomerVerification(parsed.email, result.token);
221
- return { state: "verification_required" };
290
+ const result = await registerWithProfile(parsed);
291
+ return result.state === "success" ? { addressSaved: result.addressSaved, sessionToken: result.sessionToken, state: result.state } : result;
292
+ }, { endSessionOnUnauthorized: false });
293
+ },
294
+ /**
295
+ * Partner (e.g. therapist) registration: the account with its company
296
+ * address as default address, then the partner application from that
297
+ * address. Like the plain registration it counts as registered even if a
298
+ * later step fails (`addressSaved` / `applicationSubmitted` false). While
299
+ * the e-mail is unconfirmed, address and application wait until the
300
+ * first login. Refused up front while the partner portal is off.
301
+ */
302
+ async registerPartnerWithProfile(data) {
303
+ const parsed = partnerRegistrationProfileSchema.parse(data);
304
+ return runMedusaAction(async () => {
305
+ if (!isPluginFeatureEnabled(await pluginFeatures.loadPluginFeatures(), "affiliate", "partner_portal")) {
306
+ throw new StorefrontError("partner_registration.unavailable");
222
307
  }
223
- const token = getAuthenticationToken(result);
224
- if (!token) {
225
- throw new StorefrontError("auth.registration_unsupported_step");
308
+ const application = { confirmed_without_vat_number: parsed.confirmed_without_vat_number };
309
+ const result = await registerWithProfile(parsed, { [PENDING_PARTNER_APPLICATION_KEY]: application });
310
+ if (result.state !== "success") {
311
+ return result;
226
312
  }
227
- await transferActiveCartToCustomer(createAuthenticatedMedusaClient(token), { id: customer.id, email: parsed.email });
228
- await session.setMedusaAuthToken(token);
229
- const addressSaved = parsed.address ? await storeRegistrationAddress(token, parsed, parsed.address) : true;
230
- return { addressSaved, state: "success", sessionToken: token };
313
+ const applicationSubmitted = result.addressId ? await submitPartnerApplication(result.sessionToken, result.addressId, Boolean(parsed.address.vat_number), application) : false;
314
+ return { addressSaved: result.addressSaved, applicationSubmitted, sessionToken: result.sessionToken, state: result.state };
231
315
  }, { endSessionOnUnauthorized: false });
232
316
  },
233
317
  // The backend answers 202 for every address (no account enumeration) and
@@ -63,12 +63,24 @@ export declare function createStorefrontServer(config: StorefrontServerConfig):
63
63
  }>>;
64
64
  registerCustomerWithProfile(data: import("../core/form-values.js").CustomerRegistrationProfileValues): Promise<import("../core/action-result.js").MedusaActionResult<{
65
65
  state: "verification_required";
66
+ addressId?: undefined;
66
67
  addressSaved?: undefined;
67
68
  sessionToken?: undefined;
68
69
  } | {
69
70
  addressSaved: boolean;
71
+ sessionToken: string;
70
72
  state: "success";
73
+ }>>;
74
+ registerPartnerWithProfile(data: import("../core/form-values.js").PartnerRegistrationProfileValues): Promise<import("../core/action-result.js").MedusaActionResult<{
75
+ state: "verification_required";
76
+ addressId?: undefined;
77
+ addressSaved?: undefined;
78
+ sessionToken?: undefined;
79
+ } | {
80
+ addressSaved: boolean;
81
+ applicationSubmitted: boolean;
71
82
  sessionToken: string;
83
+ state: "success";
72
84
  }>>;
73
85
  requestLoginCode(data: import("@hartl-services/medusa-contracts/types/customer-auth-store").RequestLoginCodeRequest): Promise<import("../core/action-result.js").MedusaActionResult<void>>;
74
86
  loginWithCode(data: import("@hartl-services/medusa-contracts/types/customer-auth-store").LoginWithCodeRequest): Promise<import("../core/action-result.js").MedusaActionResult<{
@@ -109,6 +121,8 @@ export declare function createStorefrontServer(config: StorefrontServerConfig):
109
121
  verifyCustomerAddressTaxIdentification(addressId: string): Promise<import("../core/action-result.js").MedusaActionResult<import("@hartl-services/medusa-contracts/types/tax-compliance-store").SubmitCustomerAddressTaxIdentificationResponse>>;
110
122
  };
111
123
  affiliate: {
124
+ loadPartnerPortalState: () => Promise<import("@hartl-services/medusa-contracts/types/affiliate-store").StoreAffiliatePortalContextResponse["portal_state"] | null>;
125
+ isActivePartner(): Promise<boolean>;
112
126
  submitAffiliateApplication(data: import("@hartl-services/medusa-contracts/types/affiliate-store").SubmitAffiliateApplicationRequest): Promise<import("../core/action-result.js").MedusaActionResult<{
113
127
  application: {
114
128
  id: string;
@@ -26,6 +26,7 @@ export function createStorefrontServer(config) {
26
26
  const runMedusaAction = createRunMedusaAction(context);
27
27
  const pluginFeatures = createPluginFeatures(context);
28
28
  const region = createRegion(context);
29
+ const affiliate = createAffiliate(context, pluginFeatures, runMedusaAction);
29
30
  return {
30
31
  session: context.session,
31
32
  createMedusaClient: context.createMedusaClient,
@@ -34,12 +35,12 @@ export function createStorefrontServer(config) {
34
35
  pluginFeatures,
35
36
  region,
36
37
  cart: createCart(context, pluginFeatures),
37
- customer: createCustomer(context, runMedusaAction),
38
+ customer: createCustomer(context, runMedusaAction, pluginFeatures),
38
39
  checkout: createCheckout(context),
39
40
  taxCompliance: createTaxCompliance(context, pluginFeatures, runMedusaAction),
40
- affiliate: createAffiliate(context, pluginFeatures, runMedusaAction),
41
+ affiliate,
41
42
  orders: createOrders(context),
42
43
  documents: createDocuments(context),
43
- catalog: createCatalog(context, region),
44
+ catalog: createCatalog(context, region, affiliate.isActivePartner),
44
45
  };
45
46
  }