require("./chunk-9hOWP6kD.cjs");
let react = require("react");
let _tanstack_react_query = require("@tanstack/react-query");
let react_jsx_runtime = require("react/jsx-runtime");
let zustand = require("zustand");
let zustand_middleware = require("zustand/middleware");
(0, react.createContext)(null);
//#endregion
//#region ../../products/core/src/portal-products-api-context.tsx
const PortalProductsCoreContext = (0, react.createContext)(null);
function PortalProductsCoreProvider({ api, children }) {
	return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PortalProductsCoreContext.Provider, {
		value: { api },
		children
	});
}
function usePortalProductsApi() {
	const ctx = (0, react.use)(PortalProductsCoreContext);
	if (!ctx) throw new Error("usePortalProductsApi must be used within a <PortalProductsCoreProvider>");
	return ctx.api;
}
//#endregion
//#region ../../products/core/src/hooks/use-debounce.ts
function useDebounce(value, delay) {
	const [debouncedValue, setDebouncedValue] = (0, react.useState)(value);
	(0, react.useEffect)(() => {
		const timer = setTimeout(() => {
			setDebouncedValue(value);
		}, delay);
		return () => {
			clearTimeout(timer);
		};
	}, [value, delay]);
	return debouncedValue;
}
//#endregion
//#region ../../products/core/src/utils/variant-subscribable.ts
/**
* A variant is subscribable when the backend signaled it via whichever of its
* equivalent PER-VARIANT fields the serving API populates:
*   - admin / V2 API:    `allow_subscription` (computed `has_subscription_plans?`)
*   - portal-tenant API: `subscription_pricing` (per-variant, per-country plan pricing)
*
* Both signals are per-variant, so a variant lacking usable pricing stays
* non-subscribable even if its product offers plans (e.g. the plan isn't priced
* in the buyer's country). Tolerating whichever field a given API populates lets
* the portal and admin surfaces share one rule and not drift apart.
*/
function isVariantSubscribable(variant) {
	return variant?.allow_subscription === true || (variant?.subscription_pricing?.length ?? 0) > 0;
}
//#endregion
//#region ../../products/core/src/hooks/use-portal-products.ts
const portalProductKeys = {
	all: ["portal-products"],
	list: (params) => [
		...portalProductKeys.all,
		"list",
		params
	],
	detail: (id) => [
		...portalProductKeys.all,
		"detail",
		String(id)
	],
	search: (query, params) => [
		...portalProductKeys.all,
		"search",
		query,
		params
	],
	media: (productId) => [
		...portalProductKeys.all,
		"media",
		String(productId)
	]
};
function usePortalProducts(params) {
	const api = usePortalProductsApi();
	return (0, _tanstack_react_query.useQuery)({
		queryKey: portalProductKeys.list(params),
		queryFn: () => api.listProducts(params)
	});
}
function usePortalProduct(id, options) {
	const api = usePortalProductsApi();
	return (0, _tanstack_react_query.useQuery)({
		queryKey: portalProductKeys.detail(id),
		queryFn: () => api.getProduct(id),
		enabled: options?.enabled ?? true
	});
}
//#endregion
//#region ../../products/core/src/hooks/use-portal-product-catalog.ts
function usePortalProductCatalog({ perPage = 25 } = {}) {
	const api = usePortalProductsApi();
	const [searchTerm, setSearchTerm] = (0, react.useState)("");
	const debouncedSearchTerm = useDebounce(searchTerm, 300);
	const [currentSort, setCurrentSort] = (0, react.useState)("created_at_desc");
	return {
		searchTerm,
		setSearchTerm,
		debouncedSearchTerm,
		currentSort,
		setCurrentSort,
		fetchProducts: (0, react.useCallback)(async (pageParam, signal) => {
			const params = {
				limit: perPage,
				sort: currentSort
			};
			if (pageParam !== void 0) params.cursor = pageParam;
			if (signal !== void 0) params.signal = signal;
			if (debouncedSearchTerm) return api.searchProducts(debouncedSearchTerm, params);
			return api.listProducts(params);
		}, [
			api,
			debouncedSearchTerm,
			perPage,
			currentSort
		]),
		getNextPageParam: (0, react.useCallback)((lastPage, _allPages, lastPageParam) => {
			const nextCursor = lastPage.meta?.pagination?.next_cursor ?? void 0;
			if (nextCursor != null && nextCursor === lastPageParam) return;
			return nextCursor;
		}, []),
		queryKey: (0, react.useMemo)(() => [
			"portal-product-catalog",
			debouncedSearchTerm || "",
			perPage,
			currentSort
		], [
			debouncedSearchTerm,
			perPage,
			currentSort
		]),
		perPage
	};
}
//#endregion
//#region ../../products/core/src/hooks/use-portal-product-detail.ts
function usePortalProductDetail({ productId }) {
	const { data: productResponse, isLoading, error } = usePortalProduct(productId);
	const product = productResponse?.product;
	return {
		product,
		isLoading,
		error,
		images: (0, react.useMemo)(() => {
			if (!product?.images) return [];
			return product.images.map((img, idx) => ({
				id: idx,
				url: img.url ?? "",
				alt: img.alt ?? null
			}));
		}, [product?.images])
	};
}
//#endregion
//#region ../../products/core/src/utils/subscription-plans.ts
function ensureDefaultSubscriptionPlan(plans) {
	const activePlans = plans.filter((plan) => plan.active !== false);
	if (activePlans.length === 0) return plans.map((plan) => ({
		...plan,
		default: false
	}));
	if (!activePlans.some((plan) => plan.default === true)) {
		const planWithLowestId = activePlans.reduce((lowest, current) => {
			const lowestId = lowest.subscription_plan?.id || Infinity;
			return (current.subscription_plan?.id || Infinity) < lowestId ? current : lowest;
		});
		return plans.map((plan) => ({
			...plan,
			default: plan.subscription_plan?.id === planWithLowestId.subscription_plan?.id && plan.active !== false
		}));
	}
	return plans.map((plan) => ({
		...plan,
		default: plan.active !== false ? plan.default ?? false : false
	}));
}
function plansToAttributes(plans) {
	return plans.map((plan) => ({
		...plan.id !== void 0 && { id: plan.id },
		subscription_plan_id: plan.subscription_plan.id,
		default: plan.default || false,
		active: plan.active !== false
	}));
}
//#endregion
//#region ../../products/core/src/stores/use-product-store.ts
const defaultState = {
	title: "",
	description: "",
	introduction: "",
	stripped: "",
	feature_text: "",
	sku: "",
	slug: "",
	canonical_url: null,
	image_url: "",
	status: "draft",
	publish_at: null,
	price: "0",
	commission: 0,
	public: true,
	no_index: false,
	show_reviews: true,
	publish_to_retail_store: true,
	publish_to_mobile_store: true,
	publish_to_portal_shop: true,
	publish_to_share_tab: true,
	collection_ids: [],
	tag_ids: [],
	images_attributes: [],
	product_subscription_plans_attributes: [],
	product_subscription_plans: [],
	variants_attributes: [],
	bundle: false,
	track_inventory_on_bundle_items: false,
	product_bundles_attributes: [],
	option_attrs: [],
	options: [],
	metafields_attributes: [],
	metadata: {},
	search_engine_optimizer_attributes: {
		title: "",
		description: "",
		image_url: "",
		image_path: "",
		block_crawler: false
	}
};
function syncSubscriptionPlans(plans) {
	const plansWithDefault = plans.filter((plan) => plan.active !== false).length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;
	return {
		product_subscription_plans: plansWithDefault,
		product_subscription_plans_attributes: plansToAttributes(plansWithDefault)
	};
}
const extractFilenameFromUrl = (imageUrl) => {
	try {
		return new URL(imageUrl).pathname.split("/").pop() || "";
	} catch {
		return imageUrl.split("/").pop()?.split("?")[0] || "";
	}
};
const createProductStore = (set, get) => ({
	...defaultState,
	track_inventory_on_bundle_items: false,
	translations: {},
	editedTranslations: {},
	translationErrors: {},
	translationLoading: {},
	translationsFetched: false,
	errors: {},
	isValid: false,
	isDirty: false,
	setProduct: (productData) => {
		const initialImagePath = productData.image_path && !productData.image_path.includes("undefined") ? productData.image_path : productData.image_url ? extractFilenameFromUrl(productData.image_url) : void 0;
		const categoryId = productData.category_id ? parseInt(productData.category_id) : productData.category?.id;
		set({
			...productData.id !== void 0 && { id: productData.id },
			title: productData.title || "",
			description: productData.description || "",
			introduction: productData.introduction || "",
			stripped: productData.stripped || "",
			feature_text: productData.feature_text || "",
			sku: productData.sku || "",
			slug: productData.slug || "",
			canonical_url: productData.canonical_url || null,
			custom_slug: productData.custom_slug || false,
			image_url: productData.image_url || "",
			...initialImagePath !== void 0 && { image_path: initialImagePath },
			status: productData.status || "draft",
			publish_at: productData.publish_at || null,
			commission: typeof productData.commission === "string" ? parseFloat(productData.commission) : productData.commission || 0,
			public: productData.public ?? true,
			no_index: productData.no_index ?? false,
			show_reviews: productData.show_reviews ?? true,
			...productData.publish_to_retail_store !== void 0 && { publish_to_retail_store: productData.publish_to_retail_store },
			...productData.publish_to_mobile_store !== void 0 && { publish_to_mobile_store: productData.publish_to_mobile_store },
			...productData.publish_to_portal_shop !== void 0 && { publish_to_portal_shop: productData.publish_to_portal_shop },
			...productData.publish_to_share_tab !== void 0 && { publish_to_share_tab: productData.publish_to_share_tab },
			...productData.tax_category_id && { tax_category_id: productData.tax_category_id },
			...productData.international_tax_type && { international_tax_type: productData.international_tax_type },
			...categoryId !== void 0 && { category_id: categoryId },
			...productData.application_theme_template_id != null && { application_theme_template_id: productData.application_theme_template_id },
			collection_ids: productData.collections?.map((collection) => collection.id) ?? [],
			tag_ids: Array.isArray(productData.tags) ? productData.tags.map((tag) => typeof tag === "number" ? tag : tag?.id).filter(Boolean) : [],
			search_engine_optimizer_attributes: (() => {
				const seo = productData.search_engine_optimizer;
				const resolvedTitle = seo?.title || productData.title;
				return {
					...seo?.id !== void 0 && { id: seo.id },
					...resolvedTitle && { title: resolvedTitle },
					description: seo?.description || "",
					image_url: seo?.image_url || productData.image_url || "",
					image_path: seo?.image_path || productData.image_path || "",
					block_crawler: seo?.block_crawler ?? false
				};
			})(),
			images_attributes: productData.images?.map((img) => {
				const imagePath = img.image_path && !img.image_path.includes("undefined") ? img.image_path : img.image_url ? extractFilenameFromUrl(img.image_url) : void 0;
				return {
					...img.id !== void 0 && { id: img.id },
					position: img.position || 0,
					image_url: img.image_url,
					...imagePath !== void 0 && { image_path: imagePath },
					_destroy: false
				};
			}) || [],
			...productData.images && productData.images.length > 0 && (() => {
				if (productData.image_path && typeof productData.image_path === "string" && !productData.image_path.includes("undefined")) return { image_path: productData.image_path };
				const firstImage = productData.images.find((img) => img.position === 0);
				if (firstImage?.image_path && typeof firstImage.image_path === "string" && !firstImage.image_path.includes("undefined")) return { image_path: firstImage.image_path };
				return productData.image_url ? { image_path: extractFilenameFromUrl(productData.image_url) } : {};
			})(),
			product_subscription_plans: (() => {
				const plans = productData?.product_subscription_plans?.map((plan) => ({ ...plan })) || [];
				return plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;
			})(),
			product_subscription_plans_attributes: (() => {
				const plans = productData?.product_subscription_plans?.map((plan) => ({ ...plan })) || [];
				return plansToAttributes(plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans);
			})(),
			variants_attributes: productData?.variants?.filter((variant) => variant.id !== null && variant.id !== void 0).map((variant) => {
				const imagesAttributes = variant?.images?.map((image) => ({
					...image.id !== void 0 && { id: image.id },
					position: image.position || 0,
					image_url: image.image_url,
					_destroy: false
				}));
				const inventoryLevelsAttributes = variant?.inventory_levels?.filter((level) => (level.warehouse_id ?? level.warehouse?.id) != null).map((level) => ({
					id: level.id,
					available: level.available,
					committed: level.committed,
					on_hand: level.on_hand,
					unavailable: level.unavailable,
					warehouse_id: level.warehouse?.id || 0,
					_destroy: false
				}));
				return {
					id: variant.id,
					title: variant.title ?? productData?.title ?? "Untitled Variant",
					option_attrs: variant.option_attrs || [],
					...variant.sku && { sku: variant.sku },
					...variant.price !== void 0 && { price: variant.price },
					track_quantity: variant.track_quantity ?? false,
					keep_selling: variant.keep_selling ?? false,
					bar_code: variant.bar_code ?? "",
					...variant.limit_subscription !== void 0 && { limit_subscription: variant.limit_subscription },
					subscription_max_qty: variant.subscription_max_qty ?? 0,
					customer_limit: variant.customer_limit ?? 0,
					is_master: variant.is_master,
					_destroy: false,
					...imagesAttributes && { images_attributes: imagesAttributes },
					...inventoryLevelsAttributes && { inventory_levels_attributes: inventoryLevelsAttributes },
					variant_countries_attributes: variant?.variant_countries ? Object.entries(variant.variant_countries).map(([iso, country]) => ({
						id: country.id ?? 0,
						active: country.active ?? true,
						...country.country_id !== void 0 && { country_id: country.country_id },
						country_name: country.country_name ?? "",
						country_iso: iso,
						price: Number(country.price) || 0,
						subscription_price: Number(country.subscription_price) || 0,
						wholesale: Number(country.wholesale) || 0,
						wholesale_subscription_price: Number(country.wholesale_subscription_price) || 0,
						compare_price: Number(country.compare_price) || 0,
						cv: Number(country.cv) || 0,
						qv: Number(country.qv) || 0,
						pc_cv: Number(country.pc_cv) || 0,
						pc_qv: Number(country.pc_qv) || 0,
						cost_of_goods_sold: Number(country.cost_of_goods_sold) || 0,
						currency_code: country.currency_code || null,
						shipping: Number(country.shipping) || 0,
						...country.points !== void 0 && { points: country.points }
					})) : []
				};
			}) ?? [],
			bundle: (productData.product_bundles?.length ?? 0) > 0,
			track_inventory_on_bundle_items: productData.track_inventory_on_bundle_items ?? false,
			product_bundles_attributes: (productData.product_bundles || []).map((bundle) => ({
				id: bundle.id,
				bundled_variant_id: bundle.bundled_variant?.id || 0,
				bundled_variant: {
					title: bundle.bundled_variant?.title || "",
					sku: bundle.bundled_variant?.sku || null,
					price: String(bundle.bundled_variant?.price || "0"),
					price_in_currency: bundle.bundled_variant?.price_in_currency || "",
					...bundle.bundled_variant?.currency_code !== void 0 && { currency_code: bundle.bundled_variant.currency_code },
					product: {
						id: bundle.bundled_variant?.product.id || 0,
						title: bundle.bundled_variant?.product.title || "",
						image_url: bundle.bundled_variant?.product.image_url || "",
						price: bundle.bundled_variant?.product.price || "0",
						price_in_currency: bundle.bundled_variant?.product.price_in_currency || "",
						cv: bundle.bundled_variant?.product.cv || 0,
						qv: bundle.bundled_variant?.product.qv || 0
					}
				},
				cv: bundle.cv || 0,
				qv: bundle.qv || 0,
				quantity: bundle.quantity,
				display_externally: bundle.display_externally ?? true,
				_destroy: false
			})),
			option_attrs: productData.option_attrs || [],
			options: productData.options || [],
			metafields_attributes: (productData.metafields || []).map((metafield) => ({
				id: metafield.id,
				namespace: metafield.namespace,
				key: metafield.key,
				value: metafield.value,
				value_type: metafield.value_type,
				_destroy: false
			})),
			metadata: productData.metadata || {},
			errors: {},
			isValid: false,
			isDirty: false
		});
	},
	updateSlug: (slug, isManual = true) => {
		set((state) => ({
			slug,
			custom_slug: isManual,
			search_engine_optimizer_attributes: {
				...state.search_engine_optimizer_attributes,
				title: state.search_engine_optimizer_attributes?.title || "",
				description: state.search_engine_optimizer_attributes?.description || "",
				image_url: state.search_engine_optimizer_attributes?.image_url || "",
				image_path: state.search_engine_optimizer_attributes?.image_path || "",
				block_crawler: state.search_engine_optimizer_attributes?.block_crawler ?? false
			},
			isDirty: true
		}));
	},
	updateSEO: (seo) => {
		set((state) => ({
			search_engine_optimizer_attributes: {
				...state.search_engine_optimizer_attributes,
				title: seo.title !== void 0 ? seo.title : state.search_engine_optimizer_attributes?.title || "",
				description: seo.description !== void 0 ? seo.description : state.search_engine_optimizer_attributes?.description || "",
				image_url: seo.image_url !== void 0 ? seo.image_url : state.search_engine_optimizer_attributes?.image_url || "",
				image_path: seo.image_path !== void 0 ? seo.image_path : state.search_engine_optimizer_attributes?.image_path || "",
				block_crawler: seo.block_crawler !== void 0 ? seo.block_crawler : state.search_engine_optimizer_attributes?.block_crawler ?? false
			},
			isDirty: true
		}));
	},
	updateField: (key, value, options) => {
		const { shouldValidate = false, shouldClearError = true, markDirty = true } = options || {};
		set((state) => {
			if (key === "product_subscription_plans") return {
				...state,
				...syncSubscriptionPlans(value),
				errors: shouldClearError ? {
					...state.errors,
					[key]: void 0
				} : state.errors,
				isDirty: markDirty ? true : state.isDirty
			};
			return {
				...state,
				[key]: value,
				errors: shouldClearError ? {
					...state.errors,
					[key]: void 0
				} : state.errors,
				isDirty: markDirty ? true : state.isDirty
			};
		});
		if (shouldValidate) get().validateField(key);
	},
	updatePartial: (updates) => {
		set((state) => {
			if (updates.product_subscription_plans) return {
				...state,
				...updates,
				...syncSubscriptionPlans(updates.product_subscription_plans),
				errors: {
					...state.errors,
					...Object.keys(updates).reduce((acc, key) => {
						acc[key] = void 0;
						return acc;
					}, {})
				},
				isDirty: true
			};
			return {
				...state,
				...updates,
				errors: {
					...state.errors,
					...Object.keys(updates).reduce((acc, key) => {
						acc[key] = void 0;
						return acc;
					}, {})
				},
				isDirty: true
			};
		});
	},
	updateArrayItem: (arrayKey, itemId, updatedItem, idField = "id") => {
		set((state) => {
			const updatedArray = (Array.isArray(state[arrayKey]) ? state[arrayKey] : []).map((item) => {
				if (typeof item === "object" && item !== null && idField in item && item[idField] === itemId) return updatedItem;
				return item;
			});
			if (arrayKey === "product_subscription_plans") return {
				...state,
				...syncSubscriptionPlans(updatedArray),
				errors: {
					...state.errors,
					[arrayKey]: void 0
				},
				isDirty: true
			};
			return {
				...state,
				[arrayKey]: updatedArray,
				errors: {
					...state.errors,
					[arrayKey]: void 0
				},
				isDirty: true
			};
		});
	},
	reset: () => {
		set({
			...defaultState,
			track_inventory_on_bundle_items: false,
			custom_slug: false,
			errors: {},
			isValid: false,
			isDirty: false
		});
	},
	validateField: (field) => {
		const fieldValue = get()[field];
		const hasValue = fieldValue !== void 0 && fieldValue !== null && fieldValue !== "";
		set((state) => ({
			errors: {
				...state.errors,
				[field]: hasValue ? void 0 : `${field} is required`
			},
			isValid: hasValue && Object.keys(state.errors).every((key) => key === field || !state.errors[key])
		}));
	},
	validateRequired: () => {
		const state = get();
		const errors = {};
		if (!state.title) errors.title = "Title is required";
		if (Object.keys(errors).length > 0) {
			set({
				errors,
				isValid: false
			});
			return false;
		}
		set({
			errors: {},
			isValid: true
		});
		return true;
	},
	clearErrors: () => {
		set({
			errors: {},
			isValid: false
		});
	},
	clearFieldError: (field) => {
		set((state) => ({ errors: {
			...state.errors,
			[field]: void 0
		} }));
	},
	markClean: () => {
		set({ isDirty: false });
	},
	setTranslationLoading: (languageIso, loading) => {
		set((state) => ({ translationLoading: {
			...state.translationLoading,
			[languageIso]: loading
		} }));
	},
	setTranslationData: (languageIso, data) => {
		set((state) => ({
			translations: {
				...state.translations,
				[languageIso]: data
			},
			translationLoading: {
				...state.translationLoading,
				[languageIso]: false
			}
		}));
	},
	updateTranslationField: (languageIso, field, value) => {
		set((state) => {
			const originalValue = state.translations[languageIso]?.[field];
			let error;
			if (field === "title" && value === "" && originalValue && originalValue.trim() !== "") error = "Title is required";
			return {
				editedTranslations: {
					...state.editedTranslations,
					[languageIso]: {
						...state.editedTranslations[languageIso],
						[field]: value
					}
				},
				translationErrors: {
					...state.translationErrors,
					[languageIso]: {
						...state.translationErrors[languageIso],
						[field]: error
					}
				}
			};
		});
	},
	getTranslation: (languageIso, field) => {
		const state = get();
		return state.editedTranslations[languageIso]?.[field] ?? state.translations[languageIso]?.[field];
	},
	getOriginalTranslation: (languageIso, field) => {
		return get().translations[languageIso]?.[field];
	},
	getEditedTranslation: (languageIso, field) => {
		return get().editedTranslations[languageIso]?.[field];
	},
	setTranslationError: (languageIso, field, error) => {
		set((state) => ({ translationErrors: {
			...state.translationErrors,
			[languageIso]: {
				...state.translationErrors[languageIso],
				[field]: error
			}
		} }));
	},
	getTranslationError: (languageIso, field) => {
		return get().translationErrors[languageIso]?.[field];
	},
	isTranslationLoading: (languageIso) => {
		return get().translationLoading[languageIso] ?? false;
	},
	resetTranslations: () => {
		set({
			translations: {},
			editedTranslations: {},
			translationErrors: {},
			translationLoading: {},
			translationsFetched: false
		});
	},
	setTranslationsFetched: (fetched) => {
		set({ translationsFetched: fetched });
	}
});
typeof process !== "undefined" && process.env?.NODE_ENV === "development" ? (0, zustand.create)()((0, zustand_middleware.devtools)(createProductStore, { name: "product-store" })) : (0, zustand.create)()(createProductStore);
(0, zustand.create)()((set, get) => ({
	draftData: null,
	isFromSettings: false,
	navigationTarget: null,
	saveDraft: (data) => {
		const formData = data;
		if (formData?.title || formData?.description || formData?.sku || formData?.product_subscription_plans && formData.product_subscription_plans.length > 0) set({ draftData: data });
	},
	getDraft: () => {
		const { draftData, isFromSettings, navigationTarget } = get();
		if (!draftData) return null;
		if (isFromSettings && navigationTarget) return draftData;
		set({ draftData: null });
		return null;
	},
	clearDraft: () => {
		const { draftData } = get();
		if (draftData) set({ draftData: null });
	},
	setFromSettings: (value) => {
		set({ isFromSettings: value });
	},
	setNavigationTarget: (target) => {
		set({ navigationTarget: target });
	},
	reset: () => {
		set({
			draftData: null,
			isFromSettings: false,
			navigationTarget: null
		});
	}
}));
//#endregion
//#region ../../products/core/src/utils/product-helpers.ts
function getProductImageUrl(product) {
	if (!product) return null;
	if (Array.isArray(product.images) && product.images.length > 0) {
		const primaryImage = product.images.toSorted((a, b) => (a.position ?? 0) - (b.position ?? 0))[0];
		if (primaryImage?.image_url) return primaryImage.image_url;
	}
	return product.image_url ?? null;
}
//#endregion
//#region ../../products/core/src/utils/product-price.ts
function stripParentheticalText(text) {
	if (!text) return null;
	return text.replace(/\s*\([^)]*\)/g, "").trim();
}
function isShopVariantCountry(vc) {
	return vc !== void 0 && "display_wholesale_subscription_price" in vc;
}
function isAdminProduct(product) {
	return "display_price" in product;
}
function isVariantCountriesRecord(vc) {
	return vc !== null && typeof vc === "object" && !Array.isArray(vc);
}
function determineProductPrice(product, countryIso) {
	const { variants } = product;
	const selectedVariant = variants?.find((v) => {
		if (isVariantCountriesRecord(v.variant_countries)) return v.variant_countries[countryIso]?.active;
		return false;
	}) || variants?.[0] || null;
	let variantCountry;
	if (countryIso && selectedVariant?.variant_countries) {
		const variantCountries = selectedVariant.variant_countries;
		if (Array.isArray(variantCountries)) variantCountry = variantCountries.find((v) => v?.country?.iso === countryIso);
		else if (isVariantCountriesRecord(variantCountries)) variantCountry = variantCountries[countryIso];
	}
	if (selectedVariant?.subscription_only) return { repPrice: isShopVariantCountry(variantCountry) ? variantCountry.display_wholesale_subscription_price : void 0 };
	const price = isShopVariantCountry(variantCountry) ? variantCountry.display_price : isAdminProduct(product) ? product.display_price : void 0;
	const repPrice = isShopVariantCountry(variantCountry) ? variantCountry.display_wholesale : void 0;
	return {
		repPrice: stripParentheticalText(repPrice),
		price: price === repPrice ? null : stripParentheticalText(price)
	};
}
//#endregion
//#region ../../products/core/src/utils/format-portal-price.ts
/**
* Format a single portal product price (a decimal string) as a localized
* currency string. Returns null for an empty/missing price; falls back to a
* plain concatenation when the value isn't numeric or the currency is invalid.
*/
function formatPortalPrice(price, currency) {
	if (!price) return null;
	const numericPrice = Number(price);
	if (Number.isNaN(numericPrice)) return `${currency ?? ""}${price}`;
	try {
		return new Intl.NumberFormat(void 0, {
			style: "currency",
			currency: currency || "USD"
		}).format(numericPrice);
	} catch {
		return `$${price}`;
	}
}
/**
* Format a bundle's min–max price range. Collapses to a single price when min
* and max are equal, and returns null when neither end resolves (the caller
* then falls back to the single non-zero price so a bundle never renders as
* free).
*/
function formatPortalPriceRange(priceRange, currency) {
	if (!priceRange) return null;
	const min = formatPortalPrice(priceRange.min, currency);
	const max = formatPortalPrice(priceRange.max, currency);
	if (min && max) return min === max ? min : `${min} – ${max}`;
	return min ?? max;
}
//#endregion
//#region ../../products/core/src/utils/format-savings.ts
function formatSavings({ wholesalePrice, wholesaleSubscriptionPrice, mode, currency, locale }) {
	if (wholesalePrice === void 0 || wholesaleSubscriptionPrice === void 0 || !Number.isFinite(wholesalePrice) || !Number.isFinite(wholesaleSubscriptionPrice) || wholesalePrice <= 0) return null;
	const savings = wholesalePrice - wholesaleSubscriptionPrice;
	if (savings <= 0) return null;
	if (mode === "amount") try {
		return new Intl.NumberFormat(locale, {
			style: "currency",
			currency
		}).format(savings);
	} catch {
		return `${currency} ${savings.toFixed(2)}`;
	}
	const percent = Math.round(savings / wholesalePrice * 100);
	if (percent <= 0) return null;
	if (locale !== void 0) try {
		return new Intl.NumberFormat(locale, {
			style: "percent",
			maximumFractionDigits: 0
		}).format(percent / 100);
	} catch {}
	return `${percent}%`;
}
//#endregion
//#region ../../products/core/src/utils/static-bundle.ts
/**
* A bundle is "static" when it has no customizable groups — a fixed set of
* items with nothing for the shopper to configure (Oliabo's bundles are the
* motivating case). A static bundle is functionally just a product, so the
* portal can add it straight to the in-app cart instead of sending logged-in
* shoppers to the storefront (where they lose wholesale pricing until checkout).
*
* Classification is server-authoritative: the backend computes
* `has_customizations` from `Bundle#dynamic?` and returns `false` for static
* bundles, `true` for customizable ones, and `null` for non-bundle products
* (see the portal-tenant product API). We only treat a bundle as static when it
* is explicitly `has_customizations === false`, so the helper degrades
* gracefully — until the backend populates the field, every bundle reports
* non-static and the storefront redirect is unchanged.
*/
function isStaticBundle(product) {
	return product?.is_bundle === true && product.has_customizations === false;
}
//#endregion
//#region ../../products/core/src/utils/bundle-subscription-price.ts
/**
* Resolve a bundle's per-plan subscription price (in the shopper's tier) from
* the tier-aware base `price_range` and the selected plan's adjustment, per the
* portal-tenant contract:
*   - `percentage`   → discount the base price by `price_adjustment_amount`%.
*   - `fixed_amount` → use the bundle's tier-aware `subscription_price_range`.
*   - `null`         → legacy plan with no type stored; treated as `fixed_amount`.
*
* `basePrice` is the tier base price (for a static bundle, `price_range.min`,
* which equals `max`). Returns the rounded subscription price, or `undefined`
* when it can't be resolved (no plan, missing amount/range, unknown type) — the
* caller then shows the plan without a savings figure rather than a wrong one.
*/
function bundleSubscriptionPrice(basePrice, subscriptionPriceRange, plan) {
	if (!plan) return void 0;
	if (plan.price_adjustment_type === "percentage") {
		const percent = Number(plan.price_adjustment_amount);
		if (basePrice === void 0 || !Number.isFinite(basePrice) || basePrice <= 0 || !Number.isFinite(percent) || percent <= 0 || percent >= 100) return;
		return roundToCents(basePrice * (1 - percent / 100));
	}
	if (plan.price_adjustment_type === "fixed_amount" || plan.price_adjustment_type === null) {
		const min = Number(subscriptionPriceRange?.min);
		return Number.isFinite(min) && min > 0 ? roundToCents(min) : void 0;
	}
}
function roundToCents(value) {
	return Math.round(value * 100) / 100;
}
//#endregion
//#region ../../products/core/src/utils/bundle-groups.ts
const GROUP_TYPES = ["included", "customizable"];
const SELECTION_TYPES = [
	"exact",
	"min_only",
	"max_only",
	"min_and_max"
];
function getGroupType(group) {
	return GROUP_TYPES.includes(group.group_type) ? group.group_type : null;
}
function isIncludedGroup(group) {
	return getGroupType(group) === "included";
}
function isCustomizableGroup(group) {
	return getGroupType(group) === "customizable";
}
function getSelectionType(group) {
	const value = group.selection_type;
	return value != null && SELECTION_TYPES.includes(value) ? value : null;
}
function sortGroups(groups) {
	return [...groups].sort((a, b) => a.sort_order - b.sort_order);
}
function sortItems(items) {
	return [...items].sort((a, b) => a.sort_order - b.sort_order);
}
/** Clamp a requested quantity to `[0, max_quantity]` (uncapped when max is null). */
function clampQuantity(item, quantity) {
	const lower = Math.max(0, quantity);
	return item.max_quantity == null ? lower : Math.min(lower, item.max_quantity);
}
/**
* Initial selections for a group: every item of an included group, or the
* `is_default` items of a customizable group, each at its (clamped) quantity.
* `subscribe` is seeded on when the item or group forces a subscription.
*
* Items unavailable for the shopper are skipped for every group type: an
* unavailable item can't be purchased, and its remove control is disabled in
* the UI, so pre-selecting it strands it (CURRENT-1394 finding #6). Skipping it
* here also keeps this in step with `getWholeGroupSelections` (the re-pick
* path), so a branch has the same items whether seeded on load or re-chosen.
*/
function getDefaultSelectionsForGroup(group) {
	const forceGroup = group.force_subscriptions === true;
	const included = isIncludedGroup(group);
	const result = {};
	for (const item of group.bundle_group_items) {
		if (item.available === false) continue;
		if (!included && item.is_default !== true) continue;
		result[item.variant_id] = {
			quantity: clampQuantity(item, item.quantity),
			subscribe: forceGroup || item.force_subscription === true
		};
	}
	return result;
}
/**
* The "whole group is chosen" selection used when a mutually-exclusive branch
* is picked as a unit (the "Choose this group" affordance): every available
* item of an included group; the `is_default` items of a customizable group,
* or its first available item when none are marked default (so choosing the
* branch always activates it). Unavailable items are skipped — they can't be
* purchased. Mirrors the storefront theme's exclusive-branch fill rules.
*/
function getWholeGroupSelections(group) {
	const forceGroup = group.force_subscriptions === true;
	const available = group.bundle_group_items.filter((item) => item.available !== false);
	let source;
	if (isIncludedGroup(group)) source = available;
	else {
		const defaults = available.filter((item) => item.is_default === true);
		source = defaults.length > 0 ? defaults : available.slice(0, 1);
	}
	const result = {};
	for (const item of source) result[item.variant_id] = {
		quantity: clampQuantity(item, item.quantity) || 1,
		subscribe: forceGroup || item.force_subscription === true
	};
	return result;
}
/** Total selected quantity (summed units) in a group. */
function selectionCount(selection) {
	if (!selection) return 0;
	return Object.values(selection).reduce((sum, s) => sum + Math.max(0, s.quantity), 0);
}
function exactTarget(group) {
	return group.min_selections ?? group.max_selections ?? 0;
}
/** Maximum total quantity a group accepts, or `Infinity` when unbounded. */
function groupCapacity(group) {
	if (isIncludedGroup(group)) return Infinity;
	switch (getSelectionType(group)) {
		case "exact": return exactTarget(group);
		case "max_only":
		case "min_and_max": return group.max_selections ?? Infinity;
		default: return Infinity;
	}
}
/** Whether the group's selection rule is currently satisfied. Included groups always are. */
function isGroupComplete(group, count) {
	if (isIncludedGroup(group)) return true;
	switch (getSelectionType(group)) {
		case "exact": return count === exactTarget(group);
		case "min_only": return count >= (group.min_selections ?? 0);
		case "max_only": return count <= (group.max_selections ?? Infinity);
		case "min_and_max": return count >= (group.min_selections ?? 0) && count <= (group.max_selections ?? Infinity);
		default: return true;
	}
}
/** Whether another item may still be added to the group given the current count. */
function canAddMoreToGroup(group, count) {
	if (isIncludedGroup(group)) return false;
	switch (getSelectionType(group)) {
		case "exact": return count < exactTarget(group);
		case "max_only":
		case "min_and_max": return count < (group.max_selections ?? Infinity);
		case "min_only": return true;
		default: return true;
	}
}
/** A group that allows at most one selection (renders as a radio, replaces on pick). */
function isSingleSelectGroup(group) {
	if (!isCustomizableGroup(group)) return false;
	if (group.max_selections === 1) return true;
	return getSelectionType(group) === "exact" && exactTarget(group) === 1;
}
/**
* Normalize `bundle_config.mutually_exclusive_groups` to plain arrays of group
* `sort_order` values, accepting both the bare-pair (legacy) and `{ ids }`
* object forms. Malformed / empty entries are dropped.
*/
function resolveExclusiveSets(config) {
	const raw = config?.mutually_exclusive_groups;
	if (!Array.isArray(raw)) return [];
	const sets = [];
	for (const entry of raw) if (Array.isArray(entry)) {
		if (entry.length) sets.push([...entry]);
	} else if (entry && Array.isArray(entry.ids) && entry.ids.length) sets.push([...entry.ids]);
	return sets;
}
/**
* Collect the admin-declared "default branch" `sort_order` values from
* `bundle_config.mutually_exclusive_groups` — the object-form entries pin which
* member of an exclusive set should be pre-selected. Bare-pair (legacy) entries
* carry no default and are ignored. Consumed by `initBundleSelection` to seed
* the declared branch instead of falling back to the lowest `sort_order`.
*/
function resolveExclusiveDefaults(config) {
	const defaults = /* @__PURE__ */ new Set();
	const raw = config?.mutually_exclusive_groups;
	if (!Array.isArray(raw)) return defaults;
	for (const entry of raw) if (!Array.isArray(entry) && entry && entry.default != null) defaults.add(entry.default);
	return defaults;
}
//#endregion
//#region ../../products/core/src/utils/bundle-selection.ts
function initBundleSelection(groups, exclusiveSets = [], defaultBranches = /* @__PURE__ */ new Set()) {
	const state = {};
	for (const group of groups) state[group.id] = getDefaultSelectionsForGroup(group);
	for (const set of exclusiveSets) {
		const seeded = groups.filter((group) => set.includes(group.sort_order) && Object.keys(state[group.id] ?? {}).length > 0).sort((a, b) => a.sort_order - b.sort_order);
		const fallback = seeded[0];
		if (seeded.length <= 1 || !fallback) continue;
		const kept = seeded.find((group) => defaultBranches.has(group.sort_order)) ?? fallback;
		for (const group of seeded) if (group.id !== kept.id) state[group.id] = {};
	}
	return state;
}
function findGroup(ctx, groupId) {
	return ctx.groups.find((g) => g.id === groupId);
}
function findItem(group, variantId) {
	return group.bundle_group_items.find((i) => i.variant_id === variantId);
}
function withGroup(state, groupId, selection) {
	return {
		...state,
		[groupId]: selection
	};
}
function omitVariant(selection, variantId) {
	const rest = {};
	for (const [key, value] of Object.entries(selection)) if (Number(key) !== variantId) rest[Number(key)] = value;
	return rest;
}
/** Clear the selections of any group that shares an exclusive set with `group`. */
function clearExclusiveSiblings(state, group, ctx) {
	const siblingSortOrders = /* @__PURE__ */ new Set();
	for (const set of ctx.exclusiveSets) {
		if (!set.includes(group.sort_order)) continue;
		for (const sortOrder of set) if (sortOrder !== group.sort_order) siblingSortOrders.add(sortOrder);
	}
	if (siblingSortOrders.size === 0) return state;
	let next = state;
	for (const sibling of ctx.groups) {
		if (!siblingSortOrders.has(sibling.sort_order)) continue;
		const current = next[sibling.id];
		if (current && Object.keys(current).length > 0) next = withGroup(next, sibling.id, {});
	}
	return next;
}
function seedSelection(group, item) {
	return {
		quantity: clampQuantity(item, item.quantity) || 1,
		subscribe: group.force_subscriptions === true || item.force_subscription === true
	};
}
/** Summed quantity of every item in the group except `variantId`. */
function sumExcept(selection, variantId) {
	let sum = 0;
	for (const [key, value] of Object.entries(selection)) if (Number(key) !== variantId) sum += Math.max(0, value.quantity);
	return sum;
}
function bundleSelectionReducer(state, action, ctx) {
	const group = findGroup(ctx, action.groupId);
	if (!group) return state;
	if (action.type === "selectGroup") return clearExclusiveSiblings(withGroup(state, action.groupId, getWholeGroupSelections(group)), group, ctx);
	if (isIncludedGroup(group)) return state;
	const item = findItem(group, action.variantId);
	if (!item) return state;
	const groupSelection = state[action.groupId] ?? {};
	const isSelected = (groupSelection[action.variantId]?.quantity ?? 0) > 0;
	switch (action.type) {
		case "toggleItem": {
			if (isSelected) return withGroup(state, action.groupId, omitVariant(groupSelection, action.variantId));
			const capacity = groupCapacity(group);
			const seed = seedSelection(group, item);
			let nextSelection;
			if (isSingleSelectGroup(group)) nextSelection = { [action.variantId]: {
				...seed,
				quantity: Math.min(seed.quantity, capacity)
			} };
			else {
				const room = capacity - sumExcept(groupSelection, action.variantId);
				if (room <= 0) return state;
				nextSelection = {
					...groupSelection,
					[action.variantId]: {
						...seed,
						quantity: Math.min(seed.quantity, room)
					}
				};
			}
			return clearExclusiveSiblings(withGroup(state, action.groupId, nextSelection), group, ctx);
		}
		case "setQuantity": {
			if (action.quantity <= 0) return withGroup(state, action.groupId, omitVariant(groupSelection, action.variantId));
			if (isSingleSelectGroup(group) && !isSelected) {
				const quantity = Math.min(clampQuantity(item, action.quantity), groupCapacity(group));
				if (quantity <= 0) return state;
				return clearExclusiveSiblings(withGroup(state, action.groupId, { [action.variantId]: {
					quantity,
					subscribe: seedSelection(group, item).subscribe
				} }), group, ctx);
			}
			const room = groupCapacity(group) - sumExcept(groupSelection, action.variantId);
			const quantity = Math.min(clampQuantity(item, action.quantity), room);
			if (quantity <= 0) return state;
			const existing = groupSelection[action.variantId];
			const next = withGroup(state, action.groupId, {
				...groupSelection,
				[action.variantId]: {
					quantity,
					subscribe: existing?.subscribe ?? seedSelection(group, item).subscribe
				}
			});
			return isSelected ? next : clearExclusiveSiblings(next, group, ctx);
		}
		case "setSubscribe": {
			const existing = groupSelection[action.variantId];
			if (!existing) return state;
			return withGroup(state, action.groupId, {
				...groupSelection,
				[action.variantId]: {
					...existing,
					subscribe: action.subscribe
				}
			});
		}
		default: return state;
	}
}
function selectedCountForGroup(state, groupId) {
	return selectionCount(state[groupId]);
}
function getItemSelection(state, groupId, variantId) {
	return state[groupId]?.[variantId];
}
/** Flatten the selection state to the cart-add payload (items with quantity > 0). */
function toCartItems(state) {
	const items = [];
	for (const [groupId, groupSelection] of Object.entries(state)) for (const [variantId, selection] of Object.entries(groupSelection)) {
		if (selection.quantity <= 0) continue;
		items.push({
			variant_id: Number(variantId),
			quantity: selection.quantity,
			subscription: selection.subscribe,
			product_bundle_group_id: Number(groupId)
		});
	}
	return items;
}
/**
* Whether every group's selection rule is satisfied for add-to-cart. A group
* in a mutually-exclusive set is exempt from its own min/exact requirement when
* a sibling in the same set has a selection: selecting one branch clears the
* others, so the non-chosen branches are intentionally empty and must not block
* completion (otherwise an exclusive bundle could never be added to cart).
*/
function isSelectionComplete(groups, state, exclusiveSets = []) {
	return groups.every((group) => {
		if (isGroupComplete(group, selectedCountForGroup(state, group.id))) return true;
		return exclusiveSets.some((set) => set.includes(group.sort_order) && groups.some((sibling) => sibling.sort_order !== group.sort_order && set.includes(sibling.sort_order) && selectedCountForGroup(state, sibling.id) > 0));
	});
}
//#endregion
//#region ../../products/core/src/hooks/use-bundle-selector.ts
/**
* Ephemeral per-screen selection state for a dynamic bundle. Seeds from admin
* defaults, enforces per-group selection rules + per-item caps + mutual
* exclusion, and exposes the flat cart payload.
*
* Selections initialize once from `groups`, so key the consuming component by
* product id — switching products should remount it with fresh defaults.
*/
function useBundleSelector({ groups, bundleConfig }) {
	const ctx = (0, react.useMemo)(() => ({
		groups,
		exclusiveSets: resolveExclusiveSets(bundleConfig),
		exclusiveDefaults: resolveExclusiveDefaults(bundleConfig)
	}), [groups, bundleConfig]);
	const [state, dispatch] = (0, react.useReducer)((current, action) => bundleSelectionReducer(current, action, ctx), groups, (initialGroups) => initBundleSelection(initialGroups, ctx.exclusiveSets, ctx.exclusiveDefaults));
	return {
		state,
		toggleItem: (0, react.useCallback)((groupId, variantId) => dispatch({
			type: "toggleItem",
			groupId,
			variantId
		}), []),
		setQuantity: (0, react.useCallback)((groupId, variantId, quantity) => dispatch({
			type: "setQuantity",
			groupId,
			variantId,
			quantity
		}), []),
		setSubscribe: (0, react.useCallback)((groupId, variantId, subscribe) => dispatch({
			type: "setSubscribe",
			groupId,
			variantId,
			subscribe
		}), []),
		selectGroup: (0, react.useCallback)((groupId) => dispatch({
			type: "selectGroup",
			groupId
		}), []),
		isSelected: (0, react.useCallback)((groupId, variantId) => (getItemSelection(state, groupId, variantId)?.quantity ?? 0) > 0, [state]),
		getQuantity: (0, react.useCallback)((groupId, variantId) => getItemSelection(state, groupId, variantId)?.quantity ?? 0, [state]),
		getSubscribe: (0, react.useCallback)((groupId, variantId) => getItemSelection(state, groupId, variantId)?.subscribe ?? false, [state]),
		groupStatus: (0, react.useCallback)((group) => {
			const count = selectedCountForGroup(state, group.id);
			return {
				count,
				isComplete: isGroupComplete(group, count),
				canAddMore: canAddMoreToGroup(group, count)
			};
		}, [state]),
		cartItems: (0, react.useMemo)(() => toCartItems(state), [state]),
		allComplete: (0, react.useMemo)(() => isSelectionComplete(groups, state, ctx.exclusiveSets), [
			groups,
			state,
			ctx.exclusiveSets
		])
	};
}
//#endregion
//#region ../../products/core/src/utils/bundle-totals.ts
function toNumber(value) {
	if (value == null) return void 0;
	const n = Number(value);
	return Number.isFinite(n) ? n : void 0;
}
function isActiveGroup(group, state) {
	return isIncludedGroup(group) || selectedCountForGroup(state, group.id) > 0;
}
function computeBundleTotals(product, groups, state, subscriptionPlan) {
	if (!groups.some((g) => g.price != null)) {
		const oneOff = toNumber(product.price_range?.min);
		return {
			mode: "bundle",
			oneOff,
			recurring: bundleSubscriptionPrice(oneOff, product.subscription_price_range, subscriptionPlan),
			cv: product.cv ?? null,
			qv: product.qv ?? null
		};
	}
	const active = groups.filter((g) => isActiveGroup(g, state));
	let oneOff = 0;
	let recurring = 0;
	let hasRecurring = false;
	let cv = 0;
	let qv = 0;
	let hasVolume = false;
	for (const group of active) {
		oneOff += toNumber(group.price) ?? 0;
		const sub = toNumber(group.subscription_price);
		if (sub != null) {
			recurring += sub;
			hasRecurring = true;
		}
		if (group.cv != null) {
			cv += group.cv;
			hasVolume = true;
		}
		if (group.qv != null) {
			qv += group.qv;
			hasVolume = true;
		}
	}
	return {
		mode: "group",
		oneOff,
		recurring: hasRecurring ? recurring : void 0,
		cv: hasVolume ? cv : null,
		qv: hasVolume ? qv : null
	};
}
//#endregion
Object.defineProperty(exports, "PortalProductsCoreProvider", {
	enumerable: true,
	get: function() {
		return PortalProductsCoreProvider;
	}
});
Object.defineProperty(exports, "bundleSubscriptionPrice", {
	enumerable: true,
	get: function() {
		return bundleSubscriptionPrice;
	}
});
Object.defineProperty(exports, "computeBundleTotals", {
	enumerable: true,
	get: function() {
		return computeBundleTotals;
	}
});
Object.defineProperty(exports, "determineProductPrice", {
	enumerable: true,
	get: function() {
		return determineProductPrice;
	}
});
Object.defineProperty(exports, "formatPortalPrice", {
	enumerable: true,
	get: function() {
		return formatPortalPrice;
	}
});
Object.defineProperty(exports, "formatPortalPriceRange", {
	enumerable: true,
	get: function() {
		return formatPortalPriceRange;
	}
});
Object.defineProperty(exports, "formatSavings", {
	enumerable: true,
	get: function() {
		return formatSavings;
	}
});
Object.defineProperty(exports, "getProductImageUrl", {
	enumerable: true,
	get: function() {
		return getProductImageUrl;
	}
});
Object.defineProperty(exports, "isIncludedGroup", {
	enumerable: true,
	get: function() {
		return isIncludedGroup;
	}
});
Object.defineProperty(exports, "isSingleSelectGroup", {
	enumerable: true,
	get: function() {
		return isSingleSelectGroup;
	}
});
Object.defineProperty(exports, "isStaticBundle", {
	enumerable: true,
	get: function() {
		return isStaticBundle;
	}
});
Object.defineProperty(exports, "isVariantSubscribable", {
	enumerable: true,
	get: function() {
		return isVariantSubscribable;
	}
});
Object.defineProperty(exports, "resolveExclusiveSets", {
	enumerable: true,
	get: function() {
		return resolveExclusiveSets;
	}
});
Object.defineProperty(exports, "selectedCountForGroup", {
	enumerable: true,
	get: function() {
		return selectedCountForGroup;
	}
});
Object.defineProperty(exports, "sortGroups", {
	enumerable: true,
	get: function() {
		return sortGroups;
	}
});
Object.defineProperty(exports, "sortItems", {
	enumerable: true,
	get: function() {
		return sortItems;
	}
});
Object.defineProperty(exports, "useBundleSelector", {
	enumerable: true,
	get: function() {
		return useBundleSelector;
	}
});
Object.defineProperty(exports, "usePortalProduct", {
	enumerable: true,
	get: function() {
		return usePortalProduct;
	}
});
Object.defineProperty(exports, "usePortalProductCatalog", {
	enumerable: true,
	get: function() {
		return usePortalProductCatalog;
	}
});
Object.defineProperty(exports, "usePortalProductDetail", {
	enumerable: true,
	get: function() {
		return usePortalProductDetail;
	}
});
Object.defineProperty(exports, "usePortalProducts", {
	enumerable: true,
	get: function() {
		return usePortalProducts;
	}
});
Object.defineProperty(exports, "usePortalProductsApi", {
	enumerable: true,
	get: function() {
		return usePortalProductsApi;
	}
});

//# sourceMappingURL=src-BRyZgUFh.cjs.map